001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant.taskdefs;
020:
021: import java.io.File;
022: import java.io.FileInputStream;
023: import java.io.InputStreamReader;
024: import java.io.FileOutputStream;
025: import java.io.OutputStreamWriter;
026: import java.io.IOException;
027: import java.io.PrintWriter;
028: import java.util.Enumeration;
029:
030: import org.apache.tools.ant.BuildException;
031: import org.apache.tools.ant.Project;
032: import org.apache.tools.ant.Task;
033: import org.apache.tools.ant.util.FileUtils;
034: import org.apache.tools.ant.types.EnumeratedAttribute;
035:
036: /**
037: * Creates a manifest file for inclusion in a JAR, Ant task wrapper
038: * around {@link Manifest Manifest}. This task can be used to write a
039: * Manifest file, optionally replacing or updating an existing file.
040: *
041: * @since Ant 1.5
042: *
043: * @ant.task category="java"
044: */
045: public class ManifestTask extends Task {
046:
047: /**
048: * Holds the real data.
049: */
050: private Manifest nestedManifest = new Manifest();
051:
052: /**
053: * The file to which the manifest should be written when used as a task
054: */
055: private File manifestFile;
056:
057: /**
058: * The mode with which the manifest file is written
059: */
060: private Mode mode;
061:
062: /**
063: * The encoding of the manifest file
064: */
065: private String encoding;
066:
067: /**
068: * Helper class for Manifest's mode attribute.
069: */
070: public static class Mode extends EnumeratedAttribute {
071: /**
072: * Get Allowed values for the mode attribute.
073: *
074: * @return a String array of the allowed values.
075: */
076: public String[] getValues() {
077: return new String[] { "update", "replace" };
078: }
079: }
080:
081: /**
082: * Default constructor
083: */
084: public ManifestTask() {
085: mode = new Mode();
086: mode.setValue("replace");
087: }
088:
089: /**
090: * Add a section to the manifest
091: *
092: * @param section the manifest section to be added
093: *
094: * @exception ManifestException if the section is not valid.
095: */
096: public void addConfiguredSection(Manifest.Section section)
097: throws ManifestException {
098: nestedManifest.addConfiguredSection(section);
099: }
100:
101: /**
102: * Add an attribute to the manifest - it is added to the main section.
103: *
104: * @param attribute the attribute to be added.
105: *
106: * @exception ManifestException if the attribute is not valid.
107: */
108: public void addConfiguredAttribute(Manifest.Attribute attribute)
109: throws ManifestException {
110: nestedManifest.addConfiguredAttribute(attribute);
111: }
112:
113: /**
114: * The name of the manifest file to create/update.
115: * Required if used as a task.
116: * @param f the Manifest file to be written
117: */
118: public void setFile(File f) {
119: manifestFile = f;
120: }
121:
122: /**
123: * The encoding to use for reading in an existing manifest file
124: * @param encoding the manifest file encoding.
125: */
126: public void setEncoding(String encoding) {
127: this .encoding = encoding;
128: }
129:
130: /**
131: * Update policy: either "update" or "replace"; default is "replace".
132: * @param m the mode value - update or replace.
133: */
134: public void setMode(Mode m) {
135: mode = m;
136: }
137:
138: /**
139: * Create or update the Manifest when used as a task.
140: *
141: * @throws BuildException if the manifest cannot be written.
142: */
143: public void execute() throws BuildException {
144: if (manifestFile == null) {
145: throw new BuildException("the file attribute is required");
146: }
147:
148: Manifest toWrite = Manifest.getDefaultManifest();
149: Manifest current = null;
150: BuildException error = null;
151:
152: if (manifestFile.exists()) {
153: FileInputStream fis = null;
154: InputStreamReader isr = null;
155: try {
156: fis = new FileInputStream(manifestFile);
157: if (encoding == null) {
158: isr = new InputStreamReader(fis, "UTF-8");
159: } else {
160: isr = new InputStreamReader(fis, encoding);
161: }
162: current = new Manifest(isr);
163: } catch (ManifestException m) {
164: error = new BuildException("Existing manifest "
165: + manifestFile + " is invalid", m,
166: getLocation());
167: } catch (IOException e) {
168: error = new BuildException("Failed to read "
169: + manifestFile, e, getLocation());
170: } finally {
171: FileUtils.close(isr);
172: }
173: }
174:
175: //look for and print warnings
176: for (Enumeration e = nestedManifest.getWarnings(); e
177: .hasMoreElements();) {
178: log("Manifest warning: " + (String) e.nextElement(),
179: Project.MSG_WARN);
180: }
181: try {
182: if (mode.getValue().equals("update")
183: && manifestFile.exists()) {
184: if (current != null) {
185: toWrite.merge(current);
186: } else if (error != null) {
187: throw error;
188: }
189: }
190:
191: toWrite.merge(nestedManifest);
192: } catch (ManifestException m) {
193: throw new BuildException("Manifest is invalid", m,
194: getLocation());
195: }
196:
197: if (toWrite.equals(current)) {
198: log("Manifest has not changed, do not recreate",
199: Project.MSG_VERBOSE);
200: return;
201: }
202:
203: PrintWriter w = null;
204: try {
205: FileOutputStream fos = new FileOutputStream(manifestFile);
206: OutputStreamWriter osw = new OutputStreamWriter(fos,
207: Manifest.JAR_ENCODING);
208: w = new PrintWriter(osw);
209: toWrite.write(w);
210: } catch (IOException e) {
211: throw new BuildException("Failed to write " + manifestFile,
212: e, getLocation());
213: } finally {
214: if (w != null) {
215: w.close();
216: }
217: }
218: }
219:
220: }
|