001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 2000, 2001, 2002, 2003 Jesse Stockall. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution, if
019: * any, must include the following acknowlegement:
020: * "This product includes software developed by the
021: * Apache Software Foundation (http://www.apache.org/)."
022: * Alternately, this acknowlegement may appear in the software itself,
023: * if and wherever such third-party acknowlegements normally appear.
024: *
025: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
026: * Foundation" must not be used to endorse or promote products derived
027: * from this software without prior written permission. For written
028: * permission, please contact apache@apache.org.
029: *
030: * 5. Products derived from this software may not be called "Apache"
031: * nor may "Apache" appear in their names without prior written
032: * permission of the Apache Group.
033: *
034: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
038: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
039: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
040: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
041: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
042: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
043: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
044: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
045: * SUCH DAMAGE.
046: * ====================================================================
047: *
048: */
049: package org.apache.tools.ant.taskdefs.optional.genjar;
050:
051: import java.io.File;
052: import java.io.IOException;
053: import java.util.ArrayList;
054: import java.util.Date;
055: import java.util.Enumeration;
056: import java.util.List;
057: import java.util.jar.JarFile;
058: import java.util.jar.Manifest;
059: import java.util.zip.ZipEntry;
060:
061: import org.apache.tools.ant.BuildException;
062:
063: import org.apache.tools.ant.types.DataType;
064: import org.apache.tools.ant.types.Path;
065:
066: /**
067: * This class encapsulates the concept of a library - either a set of files in a directory or a
068: * jar's content. If a directory is specified, all files in that directory tree are loaded into the
069: * jar. If a jar is specified, then all files from that jar are copied into the target jar (except
070: * the manifest file).
071: *
072: * @author Original Code: <a href="mailto:jake@riggshill.com">John W. Kohler </a>
073: * @author Jesse Stockall
074: * @version $Revision: 1.8 $ $Date: 2003/03/06 01:22:01 $
075: */
076: public class LibrarySpec extends DataType implements JarSpec {
077: private File baseDir = null;
078: private String basePath = null;
079: private Path classpath = null;
080: private File jar = null;
081: private String dirSpec = null; // the original directory specified
082: private File dir = null; // the actual dir to use
083: private List jarEntries = new ArrayList();
084: private String chopPath = null;
085:
086: /**
087: * Constructor for the LibrarySpec object
088: *
089: * @param baseDir Description of the Parameter
090: * @param classpath Description of the Parameter
091: */
092: public LibrarySpec(File baseDir, Path classpath) {
093: this .baseDir = baseDir;
094: this .basePath = baseDir.toString();
095: this .classpath = classpath;
096: }
097:
098: /**
099: * Gets the pathElement attribute of the LibrarySpec object
100: *
101: * @return The pathElement value
102: */
103: public Path getPathElement() {
104: return classpath;
105: }
106:
107: /**
108: * Gets the jarEntries attribute of the LibrarySpec object
109: *
110: * @return The jarEntries value
111: */
112: public List getJarEntries() {
113: return jarEntries;
114: }
115:
116: /**
117: * Gets the name of the resource.
118: *
119: * @return Thr name
120: */
121: public String getName() {
122: return jar.getName();
123: }
124:
125: /**
126: * Sets the jar attribute.
127: *
128: * @param file The file to include as a library.
129: * @throws BuildException Description of the Exception
130: */
131: public void setJar(String file) throws BuildException {
132: if (dir != null) {
133: throw new BuildException(
134: "GenJar: Can't specify both file and dir in a <library> element");
135: }
136:
137: File jarFile;
138: //
139: // try as an absolute path first - if not found
140: // then try as a relative path - if still not
141: // found then puke
142: //
143: jarFile = new File(file);
144: if (!jarFile.exists()) {
145: jarFile = new File(baseDir, file);
146: if (!jarFile.exists()) {
147: throw new BuildException(
148: "GenJar: specified library jar not found ("
149: + file + ")");
150: }
151: }
152: this .jar = jarFile;
153: classpath.setLocation(jarFile);
154: }
155:
156: /**
157: * Sets the dir attribute.
158: *
159: * @param dir The directory to load files from.
160: */
161: public void setDir(String dir) {
162: File dirFile = null;
163:
164: // Add the library dir path to the classpath
165: // so files can be found with out a classpath being set.
166: classpath.setLocation(new File(dir));
167:
168: if (jar != null) {
169: throw new BuildException(
170: "GenJar: Can't specify both file and dir in a <library> element");
171: }
172: //
173: // if they speced an absolute path then handle it w/o the
174: // project baseDir - otherwise we've gotta use the baseDir
175: // to make sure we're refering to the right thing
176: //
177: // the chopPath string is used later to remove part of each file's
178: // path so their 'jar names' are relative to the speced dir
179: //
180: if (dir.charAt(0) == '/' || dir.charAt(0) == '\\'
181: || dir.charAt(1) == ':') {
182: if (dir.endsWith("/*")) {
183: dir = dir.substring(0, dir.length() - 2);
184: chopPath = dir;
185: } else {
186: chopPath = "";
187: }
188: dirFile = new File(dir);
189: } else {
190: if (dir.endsWith("/*") || dir.endsWith("\\*")) {
191: dir = dir.substring(0, dir.length() - 2);
192: File temp = new File(baseDir, dir);
193: chopPath = temp.toString();
194: } else {
195: chopPath = baseDir.toString();
196: }
197: dirFile = new File(baseDir, dir);
198: }
199: if (!dirFile.exists()) {
200: throw new BuildException(
201: "GenJar: Specified library dir not found (" + jar
202: + ")");
203: }
204: this .dirSpec = dir;
205: this .dir = dirFile;
206: }
207:
208: /**
209: * Description of the Method
210: *
211: * @param gj Description of the Parameter
212: * @throws IOException Description of the Exception
213: */
214: public void resolve(GenJar gj) throws IOException {
215: if (jar != null) {
216: resolveJar();
217: } else {
218: resolveDir();
219: }
220: }
221:
222: /** Locate the library jar file and add all the entries to list of jar entries. */
223: private void resolveJar() {
224: try {
225: JarFile jarFile = new JarFile(jar);
226: Manifest mft = jarFile.getManifest();
227:
228: Enumeration entries = jarFile.entries();
229: while (entries.hasMoreElements()) {
230: JarEntrySpec je = new JarEntrySpec();
231: ZipEntry zentry = (ZipEntry) entries.nextElement();
232: //
233: // zip directories are not allowed - they screw
234: // up the file resolvers BIG TIME
235: //
236: if (zentry.isDirectory()) {
237: continue;
238: }
239:
240: // disallow the contents of the META-INF directory,
241: // this means Manifests, Index lists and signing information
242: String name = zentry.getName();
243: if (name.startsWith("META-INF")) {
244: continue;
245: }
246: //
247: // setup the JarEntry object and copy any existing
248: // attributes - attributes from library jar override
249: // ours
250: //
251: je.setJarName(name);
252: long size = zentry.getSize();
253: if (size != -1L) {
254: je.setAttribute("Content-Length", size);
255: }
256: if (mft != null) {
257: je.addAttributes(mft.getAttributes(name));
258: }
259: jarEntries.add(je);
260: }
261: jarFile.close();
262: } catch (IOException ioe) {
263: throw new BuildException("Error while reading library jar",
264: ioe);
265: }
266: }
267:
268: /**
269: * resolves a dir into a slew of JarEntrySpec objects this just calls _resolveDir to start the
270: * recursive descent of the dir structure
271: */
272: private void resolveDir() {
273: resolveDir(dir);
274: }
275:
276: /**
277: * Description of the Method
278: *
279: * @param root Description of the Parameter
280: */
281: private void resolveDir(File root) {
282: if (!root.isDirectory()) {
283: throw new IllegalStateException(
284: "resolveDir:root is not a dir!");
285: }
286: File[] files = root.listFiles();
287:
288: for (int i = 0; i < files.length; ++i) {
289: if (files[i].isDirectory()) {
290: resolveDir(files[i]);
291: continue;
292: }
293: JarEntrySpec je = new JarEntrySpec();
294: je.setJarName(genJarName(files[i]));
295: je.setSourceFile(files[i]);
296: je.setAttribute("Last-Modified", new Date(files[i]
297: .lastModified()));
298: je.setAttribute("Content-Length", files[i].length());
299: je.setAttribute("Content-Location", files[i]
300: .getAbsolutePath());
301: jarEntries.add(je);
302: }
303: }
304:
305: /**
306: * Strips the leading path back off of the file names we want the jar names to begin where
307: * specified in the build file - not absolute paths
308: *
309: * @param f File to strip.
310: * @return New path.
311: */
312: private String genJarName(File f) {
313: return f.getPath().replace('\\', '/').substring(
314: chopPath.length() + 1);
315: }
316: }
317: // vi:set ts=4 sw=4:
|