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: package org.apache.tools.ant.taskdefs.optional.extension;
019:
020: import java.io.File;
021: import java.io.FileOutputStream;
022: import java.io.IOException;
023: import java.util.ArrayList;
024: import java.util.Iterator;
025: import java.util.jar.Attributes;
026: import java.util.jar.Manifest;
027: import org.apache.tools.ant.BuildException;
028: import org.apache.tools.ant.MagicNames;
029: import org.apache.tools.ant.Project;
030: import org.apache.tools.ant.Task;
031:
032: /**
033: * Generates a manifest that declares all the dependencies.
034: * The dependencies are determined by looking in the
035: * specified path and searching for Extension / "Optional Package"
036: * specifications in the manifests of the jars.
037: *
038: * <p>Prior to JDK1.3, an "Optional Package" was known as an Extension.
039: * The specification for this mechanism is available in the JDK1.3
040: * documentation in the directory
041: * $JDK_HOME/docs/guide/extensions/versioning.html. Alternatively it is
042: * available online at <a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
043: * http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
044: *
045: * @ant.task name="jarlib-manifest"
046: */
047: public final class JarLibManifestTask extends Task {
048: /**
049: * Version of manifest spec that task generates.
050: */
051: private static final String MANIFEST_VERSION = "1.0";
052:
053: /**
054: * "Created-By" string used when creating manifest.
055: */
056: private static final String CREATED_BY = "Created-By";
057:
058: /**
059: * The library to display information about.
060: */
061: private File destFile;
062:
063: /**
064: * The extension supported by this library (if any).
065: */
066: private Extension extension;
067:
068: /**
069: * ExtensionAdapter objects representing
070: * dependencies required by library.
071: */
072: private final ArrayList dependencies = new ArrayList();
073:
074: /**
075: * ExtensionAdapter objects representing optional
076: * dependencies required by library.
077: */
078: private final ArrayList optionals = new ArrayList();
079:
080: /**
081: * Extra attributes the user specifies for main section
082: * in manifest.
083: */
084: private final ArrayList extraAttributes = new ArrayList();
085:
086: /**
087: * The location where generated manifest is placed.
088: *
089: * @param destFile The location where generated manifest is placed.
090: */
091: public void setDestfile(final File destFile) {
092: this .destFile = destFile;
093: }
094:
095: /**
096: * Adds an extension that this library implements.
097: *
098: * @param extensionAdapter an extension that this library implements.
099: *
100: * @throws BuildException if there is multiple extensions detected
101: * in the library.
102: */
103: public void addConfiguredExtension(
104: final ExtensionAdapter extensionAdapter)
105: throws BuildException {
106: if (null != extension) {
107: final String message = "Can not have multiple extensions defined in one library.";
108: throw new BuildException(message);
109: }
110: extension = extensionAdapter.toExtension();
111: }
112:
113: /**
114: * Adds a set of extensions that this library requires.
115: *
116: * @param extensionSet a set of extensions that this library requires.
117: */
118: public void addConfiguredDepends(final ExtensionSet extensionSet) {
119: dependencies.add(extensionSet);
120: }
121:
122: /**
123: * Adds a set of extensions that this library optionally requires.
124: *
125: * @param extensionSet a set of extensions that this library optionally requires.
126: */
127: public void addConfiguredOptions(final ExtensionSet extensionSet) {
128: optionals.add(extensionSet);
129: }
130:
131: /**
132: * Adds an attribute that is to be put in main section of manifest.
133: *
134: * @param attribute an attribute that is to be put in main section of manifest.
135: */
136: public void addConfiguredAttribute(final ExtraAttribute attribute) {
137: extraAttributes.add(attribute);
138: }
139:
140: /**
141: * Execute the task.
142: *
143: * @throws BuildException if the task fails.
144: */
145: public void execute() throws BuildException {
146: validate();
147:
148: final Manifest manifest = new Manifest();
149: final Attributes attributes = manifest.getMainAttributes();
150:
151: attributes.put(Attributes.Name.MANIFEST_VERSION,
152: MANIFEST_VERSION);
153: final String createdBy = "Apache Ant "
154: + getProject().getProperty(MagicNames.ANT_VERSION);
155: attributes.putValue(CREATED_BY, createdBy);
156:
157: appendExtraAttributes(attributes);
158:
159: if (null != extension) {
160: Extension.addExtension(extension, attributes);
161: }
162:
163: //Add all the dependency data to manifest for dependencies
164: final ArrayList depends = toExtensions(dependencies);
165: appendExtensionList(attributes, Extension.EXTENSION_LIST,
166: "lib", depends.size());
167: appendLibraryList(attributes, "lib", depends);
168:
169: //Add all the dependency data to manifest for "optional"
170: //dependencies
171: final ArrayList option = toExtensions(optionals);
172: appendExtensionList(attributes,
173: Extension.OPTIONAL_EXTENSION_LIST, "opt", option.size());
174: appendLibraryList(attributes, "opt", option);
175:
176: try {
177: final String message = "Generating manifest "
178: + destFile.getAbsoluteFile();
179: log(message, Project.MSG_INFO);
180: writeManifest(manifest);
181: } catch (final IOException ioe) {
182: throw new BuildException(ioe.getMessage(), ioe);
183: }
184: }
185:
186: /**
187: * Validate the tasks parameters.
188: *
189: * @throws BuildException if invalid parameters found
190: */
191: private void validate() throws BuildException {
192: if (null == destFile) {
193: final String message = "Destfile attribute not specified.";
194: throw new BuildException(message);
195: }
196: if (destFile.exists() && !destFile.isFile()) {
197: final String message = destFile + " is not a file.";
198: throw new BuildException(message);
199: }
200: }
201:
202: /**
203: * Add any extra attributes to the manifest.
204: *
205: * @param attributes the manifest section to write
206: * attributes to
207: */
208: private void appendExtraAttributes(final Attributes attributes) {
209: final Iterator iterator = extraAttributes.iterator();
210: while (iterator.hasNext()) {
211: final ExtraAttribute attribute = (ExtraAttribute) iterator
212: .next();
213: attributes.putValue(attribute.getName(), attribute
214: .getValue());
215: }
216: }
217:
218: /**
219: * Write out manifest to destfile.
220: *
221: * @param manifest the manifest
222: * @throws IOException if error writing file
223: */
224: private void writeManifest(final Manifest manifest)
225: throws IOException {
226: FileOutputStream output = null;
227: try {
228: output = new FileOutputStream(destFile);
229: manifest.write(output);
230: output.flush();
231: } finally {
232: if (null != output) {
233: try {
234: output.close();
235: } catch (IOException e) {
236: // ignore
237: }
238: }
239: }
240: }
241:
242: /**
243: * Append specified extensions to specified attributes.
244: * Use the extensionKey to list the extensions, usually "Extension-List:"
245: * for required dependencies and "Optional-Extension-List:" for optional
246: * dependencies. NOTE: "Optional" dependencies are not part of the
247: * specification.
248: *
249: * @param attributes the attributes to add extensions to
250: * @param extensions the list of extensions
251: * @throws BuildException if an error occurs
252: */
253: private void appendLibraryList(final Attributes attributes,
254: final String listPrefix, final ArrayList extensions)
255: throws BuildException {
256: final int size = extensions.size();
257: for (int i = 0; i < size; i++) {
258: final Extension ext = (Extension) extensions.get(i);
259: final String prefix = listPrefix + i + "-";
260: Extension.addExtension(ext, prefix, attributes);
261: }
262: }
263:
264: /**
265: * Append an attribute such as "Extension-List: lib0 lib1 lib2"
266: * using specified prefix and counting up to specified size.
267: * Also use specified extensionKey so that can generate list of
268: * optional dependencies aswell.
269: *
270: * @param size the number of librarys to list
271: * @param listPrefix the prefix for all librarys
272: * @param attributes the attributes to add key-value to
273: * @param extensionKey the key to use
274: */
275: private void appendExtensionList(final Attributes attributes,
276: final Attributes.Name extensionKey,
277: final String listPrefix, final int size) {
278: final StringBuffer sb = new StringBuffer();
279: for (int i = 0; i < size; i++) {
280: sb.append(listPrefix);
281: sb.append(i);
282: sb.append(' ');
283: }
284:
285: //add in something like
286: //"Extension-List: javahelp java3d"
287: attributes.put(extensionKey, sb.toString());
288: }
289:
290: /**
291: * Convert a list of ExtensionSet objects to extensions.
292: *
293: * @param extensionSets the list of ExtensionSets to add to list
294: * @throws BuildException if an error occurs
295: */
296: private ArrayList toExtensions(final ArrayList extensionSets)
297: throws BuildException {
298: final ArrayList results = new ArrayList();
299:
300: final int size = extensionSets.size();
301: for (int i = 0; i < size; i++) {
302: final ExtensionSet set = (ExtensionSet) extensionSets
303: .get(i);
304: final Extension[] extensions = set
305: .toExtensions(getProject());
306: for (int j = 0; j < extensions.length; j++) {
307: results.add(extensions[j]);
308: }
309: }
310:
311: return results;
312: }
313: }
|