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 38 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2001-2002 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 Conor MacNeill
  76. * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
  77. * @author <a href="mailto:j_a_fernandez@yahoo.com">Jose Alberto Fernandez</a>
  78. *
  79. * @ant.task category="java"
  80. */
  81. public class Manifest extends Task {
  82. /** The standard manifest version header */
  83. public static final String ATTRIBUTE_MANIFEST_VERSION
  84. = "Manifest-Version";
  85. /** The standard Signature Version header */
  86. public static final String ATTRIBUTE_SIGNATURE_VERSION
  87. = "Signature-Version";
  88. /** The Name Attribute is the first in a named section */
  89. public static final String ATTRIBUTE_NAME = "Name";
  90. /** The From Header is disallowed in a Manifest */
  91. public static final String ATTRIBUTE_FROM = "From";
  92. /** The Class-Path Header is special - it can be duplicated */
  93. public static final String ATTRIBUTE_CLASSPATH = "class-path";
  94. /** Default Manifest version if one is not specified */
  95. public static final String DEFAULT_MANIFEST_VERSION = "1.0";
  96. /** The max length of a line in a Manifest */
  97. public static final int MAX_LINE_LENGTH = 72;
  98. /**
  99. * Max length of a line section which is continued. need to allow
  100. * for the CRLF
  101. */
  102. public static final int MAX_SECTION_LENGTH = MAX_LINE_LENGTH - 2;
  103. /** The End-Of-Line marker in manifests */
  104. public static final String EOL = "\r\n";
  105. /**
  106. * Helper class for Manifest's mode attribute.
  107. */
  108. public static class Mode extends EnumeratedAttribute {
  109. /**
  110. * Get Allowed values for the mode attribute.
  111. *
  112. * @return a String array of the allowed values.
  113. */
  114. public String[] getValues() {
  115. return new String[] {"update", "replace"};
  116. }
  117. }
  118. /**
  119. * Class to hold manifest attributes
  120. */
  121. public static class Attribute {
  122. /** The attribute's name */
  123. private String name = null;
  124. /** The attribute's value */
  125. private Vector values = new Vector();
  126. /**
  127. * For multivalued attributes, this is the index of the attribute
  128. * currently being defined.
  129. */
  130. private int currentIndex = 0;
  131. /**
  132. * Construct an empty attribute */
  133. public Attribute() {
  134. }
  135. /**
  136. * Construct an attribute by parsing a line from the Manifest
  137. *
  138. * @param line the line containing the attribute name and value
  139. *
  140. * @throws ManifestException if the line is not valid
  141. */
  142. public Attribute(String line) throws ManifestException {
  143. parse(line);
  144. }
  145. /**
  146. * Construct a manifest by specifying its name and value
  147. *
  148. * @param name the attribute's name
  149. * @param value the Attribute's value
  150. */
  151. public Attribute(String name, String value) {
  152. this.name = name;
  153. setValue(value);
  154. }
  155. /**
  156. * @see java.lang.Object#equals
  157. */
  158. public boolean equals(Object rhs) {
  159. if (!(rhs instanceof Attribute)) {
  160. return false;
  161. }
  162. Attribute rhsAttribute = (Attribute)rhs;
  163. return (name != null && rhsAttribute.name != null &&
  164. getKey().equals(rhsAttribute.getKey()) &&
  165. values != null && values.equals(rhsAttribute.values));
  166. }
  167. /**
  168. * Parse a line into name and value pairs
  169. *
  170. * @param line the line to be parsed
  171. *
  172. * @throws ManifestException if the line does not contain a colon
  173. * separating the name and value
  174. */
  175. public void parse(String line) throws ManifestException {
  176. int index = line.indexOf(": ");
  177. if (index == -1) {
  178. throw new ManifestException("Manifest line \"" + line
  179. + "\" is not valid as it does not "
  180. + "contain a name and a value separated by ': ' ");
  181. }
  182. name = line.substring(0, index);
  183. setValue(line.substring(index + 2));
  184. }
  185. /**
  186. * Set the Attribute's name
  187. *
  188. * @param name the attribute's name
  189. */
  190. public void setName(String name) {
  191. this.name = name;
  192. }
  193. /**
  194. * Get the Attribute's name
  195. *
  196. * @return the attribute's name.
  197. */
  198. public String getName() {
  199. return name;
  200. }
  201. /**
  202. * Get the attribute's Key - its name in lower case.
  203. *
  204. * @return the attribute's key.
  205. */
  206. public String getKey() {
  207. if (name == null) {
  208. return null;
  209. }
  210. return name.toLowerCase();
  211. }
  212. /**
  213. * Set the Attribute's value
  214. *
  215. * @param value the attribute's value
  216. */
  217. public void setValue(String value) {
  218. if (currentIndex >= values.size()) {
  219. values.addElement(value);
  220. currentIndex = values.size() - 1;
  221. } else {
  222. values.setElementAt(value, currentIndex);
  223. }
  224. }
  225. /**
  226. * Get the Attribute's value
  227. *
  228. * @return the attribute's value.
  229. */
  230. public String getValue() {
  231. if (values.size() == 0) {
  232. return null;
  233. }
  234. String fullValue = "";
  235. for (Enumeration e = getValues(); e.hasMoreElements();) {
  236. String value = (String)e.nextElement();
  237. fullValue += value + " ";
  238. }
  239. return fullValue.trim();
  240. }
  241. /**
  242. * Add a new value to this attribute - making it multivalued
  243. *
  244. * @param value the attribute's additional value
  245. */
  246. public void addValue(String value) {
  247. currentIndex++;
  248. setValue(value);
  249. }
  250. /**
  251. * Get all the attribute's values
  252. *
  253. * @return an enumeration of the attributes values
  254. */
  255. public Enumeration getValues() {
  256. return values.elements();
  257. }
  258. /**
  259. * Add a continuation line from the Manifest file
  260. *
  261. * When lines are too long in a manifest, they are continued on the
  262. * next line by starting with a space. This method adds the continuation
  263. * data to the attribute value by skipping the first character.
  264. *
  265. * @param line the continuation line.
  266. */
  267. public void addContinuation(String line) {
  268. String currentValue = (String)values.elementAt(currentIndex);
  269. setValue(currentValue + line.substring(1));
  270. }
  271. /**
  272. * Write the attribute out to a print writer.
  273. *
  274. * @param writer the Writer to which the attribute is written
  275. *
  276. * @throws IOException if the attribte value cannot be written
  277. */
  278. public void write(PrintWriter writer) throws IOException {
  279. for (Enumeration e = getValues(); e.hasMoreElements();) {
  280. writeValue(writer, (String)e.nextElement());
  281. }
  282. }
  283. /**
  284. * Write a single attribute value out
  285. *
  286. * @param writer the Writer to which the attribute is written
  287. * @param value the attribute value
  288. *
  289. * @throws IOException if the attribte value cannot be written
  290. */
  291. private void writeValue(PrintWriter writer, String value)
  292. throws IOException {
  293. String line = name + ": " + value;
  294. while (line.getBytes().length > MAX_LINE_LENGTH) {
  295. // try to find a MAX_LINE_LENGTH byte section
  296. int breakIndex = MAX_SECTION_LENGTH;
  297. String section = line.substring(0, breakIndex);
  298. while (section.getBytes().length > MAX_SECTION_LENGTH
  299. && breakIndex > 0) {
  300. breakIndex--;
  301. section = line.substring(0, breakIndex);
  302. }
  303. if (breakIndex == 0) {
  304. throw new IOException("Unable to write manifest line "
  305. + name + ": " + value);
  306. }
  307. writer.print(section + EOL);
  308. line = " " + line.substring(breakIndex);
  309. }
  310. writer.print(line + EOL);
  311. }
  312. }
  313. /**
  314. * Class to represent an individual section in the
  315. * Manifest. A section consists of a set of attribute values,
  316. * separated from other sections by a blank line.
  317. */
  318. public static class Section {
  319. /** Warnings for this section */
  320. private Vector warnings = new Vector();
  321. /**
  322. * The section's name if any. The main section in a
  323. * manifest is unnamed.
  324. */
  325. private String name = null;
  326. /** The section's attributes.*/
  327. private Hashtable attributes = new Hashtable();
  328. /** Index used to retain the attribute ordering */
  329. private Vector attributeIndex = new Vector();
  330. /**
  331. * Set the Section's name
  332. *
  333. * @param name the section's name
  334. */
  335. public void setName(String name) {
  336. this.name = name;
  337. }
  338. /**
  339. * Get the Section's name
  340. *
  341. * @return the section's name.
  342. */
  343. public String getName() {
  344. return name;
  345. }
  346. /**
  347. * Read a section through a reader
  348. *
  349. * @param reader the reader from which the section is read
  350. *
  351. * @return the name of the next section if it has been read as
  352. * part of this section - This only happens if the
  353. * Manifest is malformed.
  354. *
  355. * @throws ManifestException if the section is not valid according
  356. * to the JAR spec
  357. * @throws IOException if the section cannot be read from the reader.
  358. */
  359. public String read(BufferedReader reader)
  360. throws ManifestException, IOException {
  361. Attribute attribute = null;
  362. while (true) {
  363. String line = reader.readLine();
  364. if (line == null || line.length() == 0) {
  365. return null;
  366. }
  367. if (line.charAt(0) == ' ') {
  368. // continuation line
  369. if (attribute == null) {
  370. if (name != null) {
  371. // a continuation on the first line is a
  372. // continuation of the name - concatenate this
  373. // line and the name
  374. name += line.substring(1);
  375. } else {
  376. throw new ManifestException("Can't start an "
  377. + "attribute with a continuation line " + line);
  378. }
  379. } else {
  380. attribute.addContinuation(line);
  381. }
  382. } else {
  383. attribute = new Attribute(line);
  384. String nameReadAhead = addAttributeAndCheck(attribute);
  385. if (nameReadAhead != null) {
  386. return nameReadAhead;
  387. }
  388. }
  389. }
  390. }
  391. /**
  392. * Merge in another section
  393. *
  394. * @param section the section to be merged with this one.
  395. *
  396. * @throws ManifestException if the sections cannot be merged.
  397. */
  398. public void merge(Section section) throws ManifestException {
  399. if (name == null && section.getName() != null
  400. || name != null
  401. && !(name.equalsIgnoreCase(section.getName()))) {
  402. throw new ManifestException("Unable to merge sections "
  403. + "with different names");
  404. }
  405. Enumeration e = section.getAttributeKeys();
  406. while (e.hasMoreElements()) {
  407. String attributeName = (String)e.nextElement();
  408. Attribute attribute = section.getAttribute(attributeName);
  409. if (attributeName.equals(ATTRIBUTE_CLASSPATH) &&
  410. attributes.containsKey(attributeName)) {
  411. Attribute ourClassPath = getAttribute(attributeName);
  412. Enumeration cpe = attribute.getValues();
  413. while (cpe.hasMoreElements()) {
  414. String value = (String)cpe.nextElement();
  415. ourClassPath.addValue(value);
  416. }
  417. } else {
  418. // the merge file always wins
  419. storeAttribute(attribute);
  420. }
  421. }
  422. // add in the warnings
  423. Enumeration warnEnum = section.warnings.elements();
  424. while (warnEnum.hasMoreElements()) {
  425. warnings.addElement(warnEnum.nextElement());
  426. }
  427. }
  428. /**
  429. * Write the section out to a print writer.
  430. *
  431. * @param writer the Writer to which the section is written
  432. *
  433. * @throws IOException if the section cannot be written
  434. */
  435. public void write(PrintWriter writer) throws IOException {
  436. if (name != null) {
  437. Attribute nameAttr = new Attribute(ATTRIBUTE_NAME, name);
  438. nameAttr.write(writer);
  439. }
  440. Enumeration e = getAttributeKeys();
  441. while (e.hasMoreElements()) {
  442. String key = (String)e.nextElement();
  443. Attribute attribute = getAttribute(key);
  444. attribute.write(writer);
  445. }
  446. writer.print(EOL);
  447. }
  448. /**
  449. * Get a attribute of the section
  450. *
  451. * @param attributeName the name of the attribute
  452. * @return a Manifest.Attribute instance if the attribute is
  453. * single-valued, otherwise a Vector of Manifest.Attribute
  454. * instances.
  455. */
  456. public Attribute getAttribute(String attributeName) {
  457. return (Attribute)attributes.get(attributeName.toLowerCase());
  458. }
  459. /**
  460. * Get the attribute keys.
  461. *
  462. * @return an Enumeration of Strings, each string being the lower case
  463. * key of an attribute of the section.
  464. */
  465. public Enumeration getAttributeKeys() {
  466. return attributeIndex.elements();
  467. }
  468. /**
  469. * Get the value of the attribute with the name given.
  470. *
  471. * @param attributeName the name of the attribute to be returned.
  472. *
  473. * @return the attribute's value or null if the attribute does not exist
  474. * in the section
  475. */
  476. public String getAttributeValue(String attributeName) {
  477. Attribute attribute = getAttribute(attributeName.toLowerCase());
  478. if (attribute == null) {
  479. return null;
  480. }
  481. return attribute.getValue();
  482. }
  483. /**
  484. * Remove tge given attribute from the section
  485. *
  486. * @param attributeName the name of the attribute to be removed.
  487. */
  488. public void removeAttribute(String attributeName) {
  489. String key = attributeName.toLowerCase();
  490. attributes.remove(key);
  491. attributeIndex.removeElement(key);
  492. }
  493. /**
  494. * Add an attribute to the section.
  495. *
  496. * @param attribute the attribute to be added to the section
  497. *
  498. * @exception ManifestException if the attribute is not valid.
  499. */
  500. public void addConfiguredAttribute(Attribute attribute)
  501. throws ManifestException {
  502. String check = addAttributeAndCheck(attribute);
  503. if (check != null) {
  504. throw new BuildException("Specify the section name using "
  505. + "the \"name\" attribute of the <section> element rather "
  506. + "than using a \"Name\" manifest attribute");
  507. }
  508. }
  509. /**
  510. * Add an attribute to the section
  511. *
  512. * @param attribute the attribute to be added.
  513. *
  514. * @return the value of the attribute if it is a name
  515. * attribute - null other wise
  516. *
  517. * @exception ManifestException if the attribute already
  518. * exists in this section.
  519. */
  520. public String addAttributeAndCheck(Attribute attribute)
  521. throws ManifestException {
  522. if (attribute.getName() == null || attribute.getValue() == null) {
  523. throw new BuildException("Attributes must have name and value");
  524. }
  525. if (attribute.getKey().equalsIgnoreCase(ATTRIBUTE_NAME)) {
  526. warnings.addElement("\"" + ATTRIBUTE_NAME + "\" attributes "
  527. + "should not occur in the main section and must be the "
  528. + "first element in all other sections: \""
  529. + attribute.getName() + ": " + attribute.getValue() + "\"");
  530. return attribute.getValue();
  531. }
  532. if (attribute.getKey().startsWith(ATTRIBUTE_FROM.toLowerCase())) {
  533. warnings.addElement("Manifest attributes should not start "
  534. + "with \"" + ATTRIBUTE_FROM + "\" in \""
  535. + attribute.getName() + ": " + attribute.getValue() + "\"");
  536. } else {
  537. // classpath attributes go into a vector
  538. String attributeKey = attribute.getKey();
  539. if (attributeKey.equals(ATTRIBUTE_CLASSPATH)) {
  540. Attribute classpathAttribute =
  541. (Attribute)attributes.get(attributeKey);
  542. if (classpathAttribute == null) {
  543. storeAttribute(attribute);
  544. } else {
  545. Enumeration e = attribute.getValues();
  546. while (e.hasMoreElements()) {
  547. String value = (String)e.nextElement();
  548. classpathAttribute.addValue(value);
  549. }
  550. }
  551. } else if (attributes.containsKey(attributeKey)) {
  552. throw new ManifestException("The attribute \""
  553. + attribute.getName() + "\" may not occur more "
  554. + "than once in the same section");
  555. } else {
  556. storeAttribute(attribute);
  557. }
  558. }
  559. return null;
  560. }
  561. /**
  562. * Store an attribute and update the index.
  563. *
  564. * @param attribute the attribute to be stored
  565. */
  566. private void storeAttribute(Attribute attribute) {
  567. if (attribute == null) {
  568. return;
  569. }
  570. String attributeKey = attribute.getKey();
  571. attributes.put(attributeKey, attribute);
  572. if (!attributeIndex.contains(attributeKey)) {
  573. attributeIndex.addElement(attributeKey);
  574. }
  575. }
  576. /**
  577. * Get the warnings for this section.
  578. *
  579. * @return an Enumeration of warning strings.
  580. */
  581. public Enumeration getWarnings() {
  582. return warnings.elements();
  583. }
  584. /**
  585. * @see java.lang.Object#equals
  586. */
  587. public boolean equals(Object rhs) {
  588. if (!(rhs instanceof Section)) {
  589. return false;
  590. }
  591. Section rhsSection = (Section)rhs;
  592. if (attributes.size() != rhsSection.attributes.size()) {
  593. return false;
  594. }
  595. for (Enumeration e = attributes.keys(); e.hasMoreElements();) {
  596. String attributeName = (String)e.nextElement();
  597. Object attributeValue = attributes.get(attributeName);
  598. Object rshAttributeValue
  599. = rhsSection.attributes.get(attributeName);
  600. if (!attributeValue.equals(rshAttributeValue)) {
  601. return false;
  602. }
  603. }
  604. return true;
  605. }
  606. }
  607. /** The version of this manifest */
  608. private String manifestVersion = DEFAULT_MANIFEST_VERSION;
  609. /** The main section of this manifest */
  610. private Section mainSection = new Section();
  611. /** The named sections of this manifest */
  612. private Hashtable sections = new Hashtable();
  613. /** Index of sections - used to retain order of sections in manifest */
  614. private Vector sectionIndex = new Vector();
  615. /**
  616. * The file to which the manifest should be written when used as a task
  617. */
  618. private File manifestFile;
  619. /**
  620. * The mode with which the manifest file is written
  621. */
  622. private Mode mode;
  623. /**
  624. * Construct a manifest from Ant's default manifest file.
  625. *
  626. *
  627. * @return the default manifest.
  628. * @exception BuildException if there is a problem loading the
  629. * default manifest
  630. */
  631. public static Manifest getDefaultManifest() throws BuildException {
  632. try {
  633. String defManifest = "/org/apache/tools/ant/defaultManifest.mf";
  634. InputStream in = Manifest.class.getResourceAsStream(defManifest);
  635. if (in == null) {
  636. throw new BuildException("Could not find default manifest: "
  637. + defManifest);
  638. }
  639. try {
  640. return new Manifest(new InputStreamReader(in, "ASCII"));
  641. } catch (UnsupportedEncodingException e) {
  642. return new Manifest(new InputStreamReader(in));
  643. }
  644. } catch (ManifestException e) {
  645. throw new BuildException("Default manifest is invalid !!", e);
  646. } catch (IOException e) {
  647. throw new BuildException("Unable to read default manifest", e);
  648. }
  649. }
  650. /** Construct an empty manifest */
  651. public Manifest() {
  652. mode = new Mode();
  653. mode.setValue("replace");
  654. manifestVersion = null;
  655. }
  656. /**
  657. * Read a manifest file from the given reader
  658. *
  659. * @param r is the reader from which the Manifest is read
  660. *
  661. * @throws ManifestException if the manifest is not valid according
  662. * to the JAR spec
  663. * @throws IOException if the manifest cannot be read from the reader.
  664. */
  665. public Manifest(Reader r) throws ManifestException, IOException {
  666. BufferedReader reader = new BufferedReader(r);
  667. // This should be the manifest version
  668. String nextSectionName = mainSection.read(reader);
  669. String readManifestVersion
  670. = mainSection.getAttributeValue(ATTRIBUTE_MANIFEST_VERSION);
  671. if (readManifestVersion != null) {
  672. manifestVersion = readManifestVersion;
  673. mainSection.removeAttribute(ATTRIBUTE_MANIFEST_VERSION);
  674. }
  675. String line = null;
  676. while ((line = reader.readLine()) != null) {
  677. if (line.length() == 0) {
  678. continue;
  679. }
  680. Section section = new Section();
  681. if (nextSectionName == null) {
  682. Attribute sectionName = new Attribute(line);
  683. if (!sectionName.getName().equalsIgnoreCase(ATTRIBUTE_NAME)) {
  684. throw new ManifestException("Manifest sections should "
  685. + "start with a \"" + ATTRIBUTE_NAME
  686. + "\" attribute and not \""
  687. + sectionName.getName() + "\"");
  688. }
  689. nextSectionName = sectionName.getValue();
  690. } else {
  691. // we have already started reading this section
  692. // this line is the first attribute. set it and then
  693. // let the normal read handle the rest
  694. Attribute firstAttribute = new Attribute(line);
  695. section.addAttributeAndCheck(firstAttribute);
  696. }
  697. section.setName(nextSectionName);
  698. nextSectionName = section.read(reader);
  699. addConfiguredSection(section);
  700. }
  701. }
  702. /**
  703. * Add a section to the manifest
  704. *
  705. * @param section the manifest section to be added
  706. *
  707. * @exception ManifestException if the secti0on is not valid.
  708. */
  709. public void addConfiguredSection(Section section)
  710. throws ManifestException {
  711. String sectionName = section.getName();
  712. if (sectionName == null) {
  713. throw new BuildException("Sections must have a name");
  714. }
  715. sections.put(sectionName, section);
  716. if (!sectionIndex.contains(sectionName)) {
  717. sectionIndex.addElement(sectionName);
  718. }
  719. }
  720. /**
  721. * Add an attribute to the manifest - it is added to the main section.
  722. *
  723. * @param attribute the attribute to be added.
  724. *
  725. * @exception ManifestException if the attribute is not valid.
  726. */
  727. public void addConfiguredAttribute(Attribute attribute)
  728. throws ManifestException {
  729. mainSection.addConfiguredAttribute(attribute);
  730. }
  731. /**
  732. * Merge the contents of the given manifest into this manifest
  733. *
  734. * @param other the Manifest to be merged with this one.
  735. *
  736. * @throws ManifestException if there is a problem merging the
  737. * manfest according to the Manifest spec.
  738. */
  739. public void merge(Manifest other) throws ManifestException {
  740. merge(other, false);
  741. }
  742. /**
  743. * Merge the contents of the given manifest into this manifest
  744. *
  745. * @param other the Manifest to be merged with this one.
  746. * @param overwriteMain whether to overwrite the main section
  747. * of the current manifest
  748. *
  749. * @throws ManifestException if there is a problem merging the
  750. * manfest according to the Manifest spec.
  751. */
  752. public void merge(Manifest other, boolean overwriteMain)
  753. throws ManifestException {
  754. if (other != null) {
  755. if (overwriteMain) {
  756. mainSection = other.mainSection;
  757. } else {
  758. mainSection.merge(other.mainSection);
  759. }
  760. if (other.manifestVersion != null) {
  761. manifestVersion = other.manifestVersion;
  762. }
  763. Enumeration e = other.getSectionNames();
  764. while (e.hasMoreElements()) {
  765. String sectionName = (String)e.nextElement();
  766. Section ourSection = (Section)sections.get(sectionName);
  767. Section otherSection
  768. = (Section)other.sections.get(sectionName);
  769. if (ourSection == null) {
  770. if (otherSection != null) {
  771. addConfiguredSection(otherSection);
  772. }
  773. } else {
  774. ourSection.merge(otherSection);
  775. }
  776. }
  777. }
  778. }
  779. /**
  780. * Write the manifest out to a print writer.
  781. *
  782. * @param writer the Writer to which the manifest is written
  783. *
  784. * @throws IOException if the manifest cannot be written
  785. */
  786. public void write(PrintWriter writer) throws IOException {
  787. writer.print(ATTRIBUTE_MANIFEST_VERSION + ": " + manifestVersion + EOL);
  788. String signatureVersion
  789. = mainSection.getAttributeValue(ATTRIBUTE_SIGNATURE_VERSION);
  790. if (signatureVersion != null) {
  791. writer.print(ATTRIBUTE_SIGNATURE_VERSION + ": "
  792. + signatureVersion + EOL);
  793. mainSection.removeAttribute(ATTRIBUTE_SIGNATURE_VERSION);
  794. }
  795. mainSection.write(writer);
  796. // add it back
  797. if (signatureVersion != null) {
  798. try {
  799. Attribute svAttr = new Attribute(ATTRIBUTE_SIGNATURE_VERSION,
  800. signatureVersion);
  801. mainSection.addConfiguredAttribute(svAttr);
  802. } catch (ManifestException e) {
  803. // shouldn't happen - ignore
  804. }
  805. }
  806. Enumeration e = sectionIndex.elements();
  807. while (e.hasMoreElements()) {
  808. String sectionName = (String)e.nextElement();
  809. Section section = getSection(sectionName);
  810. section.write(writer);
  811. }
  812. }
  813. /**
  814. * Convert the manifest to its string representation
  815. *
  816. * @return a multiline string with the Manifest as it
  817. * appears in a Manifest file.
  818. */
  819. public String toString() {
  820. StringWriter sw = new StringWriter();
  821. try {
  822. write(new PrintWriter(sw));
  823. } catch (IOException e) {
  824. return null;
  825. }
  826. return sw.toString();
  827. }
  828. /**
  829. * Get the warnings for this manifest.
  830. *
  831. * @return an enumeration of warning strings
  832. */
  833. public Enumeration getWarnings() {
  834. Vector warnings = new Vector();
  835. Enumeration warnEnum = mainSection.getWarnings();
  836. while (warnEnum.hasMoreElements()) {
  837. warnings.addElement(warnEnum.nextElement());
  838. }
  839. // create a vector and add in the warnings for all the sections
  840. Enumeration e = sections.elements();
  841. while (e.hasMoreElements()) {
  842. Section section = (Section)e.nextElement();
  843. Enumeration e2 = section.getWarnings();
  844. while (e2.hasMoreElements()) {
  845. warnings.addElement(e2.nextElement());
  846. }
  847. }
  848. return warnings.elements();
  849. }
  850. /**
  851. * @see java.lang.Object#equals
  852. */
  853. public boolean equals(Object rhs) {
  854. if (!(rhs instanceof Manifest)) {
  855. return false;
  856. }
  857. Manifest rhsManifest = (Manifest)rhs;
  858. if (manifestVersion == null) {
  859. if (rhsManifest.manifestVersion != null) {
  860. return false;
  861. }
  862. } else if (!manifestVersion.equals(rhsManifest.manifestVersion)) {
  863. return false;
  864. }
  865. if (sections.size() != rhsManifest.sections.size()) {
  866. return false;
  867. }
  868. if (!mainSection.equals(rhsManifest.mainSection)) {
  869. return false;
  870. }
  871. Enumeration e = sections.elements();
  872. while (e.hasMoreElements()) {
  873. Section section = (Section)e.nextElement();
  874. Section rhsSection
  875. = (Section)rhsManifest.sections.get(section.getName());
  876. if (!section.equals(rhsSection)) {
  877. return false;
  878. }
  879. }
  880. return true;
  881. }
  882. /**
  883. * The name of the manifest file to write (if used as a task).
  884. *
  885. * @param f the Manifest file to be written
  886. */
  887. public void setFile(File f) {
  888. manifestFile = f;
  889. }
  890. /**
  891. * Shall we update or replace an existing manifest?
  892. *
  893. * @param m the mode value - update or replace.
  894. */
  895. public void setMode(Mode m) {
  896. mode = m;
  897. }
  898. /**
  899. * Get the version of the manifest
  900. *
  901. * @return the manifest's version string
  902. */
  903. public String getManifestVersion() {
  904. return manifestVersion;
  905. }
  906. /**
  907. * Get the main section of the manifest
  908. *
  909. * @return the main section of the manifest
  910. */
  911. public Section getMainSection() {
  912. return mainSection;
  913. }
  914. /**
  915. * Get a particular section from the manifest
  916. *
  917. * @param name the name of the section desired.
  918. * @return the specified section or null if that section
  919. * does not exist in the manifest
  920. */
  921. public Section getSection(String name) {
  922. return (Section)sections.get(name);
  923. }
  924. /**
  925. * Get the section names in this manifest.
  926. *
  927. * @return an Enumeration of section names
  928. */
  929. public Enumeration getSectionNames() {
  930. return sectionIndex.elements();
  931. }
  932. /**
  933. * Create or update the Manifest when used as a task.
  934. *
  935. * @throws BuildException if the manifst cannot be written.
  936. */
  937. public void execute() throws BuildException {
  938. if (manifestFile == null) {
  939. throw new BuildException("the file attribute is required");
  940. }
  941. Manifest toWrite = getDefaultManifest();
  942. Manifest current = null;
  943. BuildException error = null;
  944. if (manifestFile.exists()) {
  945. FileReader f = null;
  946. try {
  947. f = new FileReader(manifestFile);
  948. current = new Manifest(f);
  949. } catch (ManifestException m) {
  950. error = new BuildException("Existing manifest " + manifestFile
  951. + " is invalid", m, location);
  952. } catch (IOException e) {
  953. error = new BuildException("Failed to read " + manifestFile,
  954. e, location);
  955. } finally {
  956. if (f != null) {
  957. try {
  958. f.close();
  959. } catch (IOException e) {}
  960. }
  961. }
  962. }
  963. try {
  964. if (mode.getValue().equals("update") && manifestFile.exists()) {
  965. if (current != null) {
  966. toWrite.merge(current);
  967. }
  968. else if (error != null) {
  969. throw error;
  970. }
  971. }
  972. toWrite.merge(this);
  973. } catch (ManifestException m) {
  974. throw new BuildException("Manifest is invalid", m, location);
  975. }
  976. if (toWrite.equals(current)) {
  977. log("Manifest has not changed, do not recreate", project.MSG_VERBOSE);
  978. return;
  979. }
  980. PrintWriter w = null;
  981. try {
  982. w = new PrintWriter(new FileWriter(manifestFile));
  983. toWrite.write(w);
  984. } catch (IOException e) {
  985. throw new BuildException("Failed to write " + manifestFile,
  986. e, location);
  987. } finally {
  988. if (w != null) {
  989. w.close();
  990. }
  991. }
  992. }
  993. }