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.types;
020:
021: import java.io.File;
022: import java.util.Map;
023: import java.util.Set;
024: import java.util.TreeMap;
025: import java.util.Iterator;
026:
027: import org.apache.tools.ant.DirectoryScanner;
028: import org.apache.tools.ant.types.resources.FileResource;
029: import org.apache.tools.ant.types.resources.FileResourceIterator;
030:
031: /**
032: * ArchiveScanner accesses the pattern matching algorithm in DirectoryScanner,
033: * which are protected methods that can only be accessed by subclassing.
034: *
035: * This implementation of FileScanner defines getIncludedFiles to return
036: * the matching archive entries.
037: *
038: * @since Ant 1.7
039: */
040: public abstract class ArchiveScanner extends DirectoryScanner {
041: // CheckStyle:VisibilityModifier OFF - bc
042:
043: /**
044: * The archive file which should be scanned.
045: */
046: protected File srcFile;
047:
048: // CheckStyle:VisibilityModifier ON
049:
050: /**
051: * The archive resource which should be scanned.
052: */
053: private Resource src;
054:
055: /**
056: * to record the last scanned zip file with its modification date
057: */
058: private Resource lastScannedResource;
059:
060: /**
061: * record list of all file zip entries
062: */
063: private TreeMap fileEntries = new TreeMap();
064:
065: /**
066: * record list of all directory zip entries
067: */
068: private TreeMap dirEntries = new TreeMap();
069:
070: /**
071: * record list of matching file zip entries
072: */
073: private TreeMap matchFileEntries = new TreeMap();
074:
075: /**
076: * record list of matching directory zip entries
077: */
078: private TreeMap matchDirEntries = new TreeMap();
079:
080: /**
081: * encoding of file names.
082: *
083: * @since Ant 1.6
084: */
085: private String encoding;
086:
087: /**
088: * Don't scan when we have no zipfile.
089: * @since Ant 1.7
090: */
091: public void scan() {
092: if (src == null) {
093: return;
094: }
095: super .scan();
096: }
097:
098: /**
099: * Sets the srcFile for scanning. This is the jar or zip file that
100: * is scanned for matching entries.
101: *
102: * @param srcFile the (non-null) archive file name for scanning
103: */
104: public void setSrc(File srcFile) {
105: setSrc(new FileResource(srcFile));
106: }
107:
108: /**
109: * Sets the src for scanning. This is the jar or zip file that
110: * is scanned for matching entries.
111: *
112: * @param src the (non-null) archive resource
113: */
114: public void setSrc(Resource src) {
115: this .src = src;
116: if (src instanceof FileResource) {
117: srcFile = ((FileResource) src).getFile();
118: }
119: }
120:
121: /**
122: * Sets encoding of file names.
123: * @param encoding the encoding format
124: * @since Ant 1.6
125: */
126: public void setEncoding(String encoding) {
127: this .encoding = encoding;
128: }
129:
130: /**
131: * Returns the names of the files which matched at least one of the
132: * include patterns and none of the exclude patterns.
133: * The names are relative to the base directory.
134: *
135: * @return the names of the files which matched at least one of the
136: * include patterns and none of the exclude patterns.
137: */
138: public String[] getIncludedFiles() {
139: if (src == null) {
140: return super .getIncludedFiles();
141: }
142: scanme();
143: Set s = matchFileEntries.keySet();
144: return (String[]) (s.toArray(new String[s.size()]));
145: }
146:
147: /**
148: * Override parent implementation.
149: * @return count of included files.
150: * @since Ant 1.7
151: */
152: public int getIncludedFilesCount() {
153: if (src == null) {
154: return super .getIncludedFilesCount();
155: }
156: scanme();
157: return matchFileEntries.size();
158: }
159:
160: /**
161: * Returns the names of the directories which matched at least one of the
162: * include patterns and none of the exclude patterns.
163: * The names are relative to the base directory.
164: *
165: * @return the names of the directories which matched at least one of the
166: * include patterns and none of the exclude patterns.
167: */
168: public String[] getIncludedDirectories() {
169: if (src == null) {
170: return super .getIncludedDirectories();
171: }
172: scanme();
173: Set s = matchDirEntries.keySet();
174: return (String[]) (s.toArray(new String[s.size()]));
175: }
176:
177: /**
178: * Override parent implementation.
179: * @return count of included directories.
180: * @since Ant 1.7
181: */
182: public int getIncludedDirsCount() {
183: if (src == null) {
184: return super .getIncludedDirsCount();
185: }
186: scanme();
187: return matchDirEntries.size();
188: }
189:
190: /**
191: * Get the set of Resources that represent files.
192: * @return an Iterator of Resources.
193: * @since Ant 1.7
194: */
195: /* package-private for now */Iterator getResourceFiles() {
196: if (src == null) {
197: return new FileResourceIterator(getBasedir(),
198: getIncludedFiles());
199: }
200: scanme();
201: return matchFileEntries.values().iterator();
202: }
203:
204: /**
205: * Get the set of Resources that represent directories.
206: * @return an Iterator of Resources.
207: * @since Ant 1.7
208: */
209: /* package-private for now */Iterator getResourceDirectories() {
210: if (src == null) {
211: return new FileResourceIterator(getBasedir(),
212: getIncludedDirectories());
213: }
214: scanme();
215: return matchDirEntries.values().iterator();
216: }
217:
218: /**
219: * Initialize DirectoryScanner data structures.
220: */
221: public void init() {
222: if (includes == null) {
223: // No includes supplied, so set it to 'matches all'
224: includes = new String[1];
225: includes[0] = "**";
226: }
227: if (excludes == null) {
228: excludes = new String[0];
229: }
230: }
231:
232: /**
233: * Matches a jar entry against the includes/excludes list,
234: * normalizing the path separator.
235: *
236: * @param path the (non-null) path name to test for inclusion
237: *
238: * @return <code>true</code> if the path should be included
239: * <code>false</code> otherwise.
240: */
241: public boolean match(String path) {
242: String vpath = path.replace('/', File.separatorChar).replace(
243: '\\', File.separatorChar);
244: return isIncluded(vpath) && !isExcluded(vpath);
245: }
246:
247: /**
248: * Get the named Resource.
249: * @param name path name of the file sought in the archive
250: * @return the resource
251: * @since Ant 1.5.2
252: */
253: public Resource getResource(String name) {
254: if (src == null) {
255: return super .getResource(name);
256: }
257: if (name.equals("")) {
258: // special case in ZIPs, we do not want this thing included
259: return new Resource("", true, Long.MAX_VALUE, true);
260: }
261: // first check if the archive needs to be scanned again
262: scanme();
263: if (fileEntries.containsKey(name)) {
264: return (Resource) fileEntries.get(name);
265: }
266: name = trimSeparator(name);
267:
268: if (dirEntries.containsKey(name)) {
269: return (Resource) dirEntries.get(name);
270: }
271: return new Resource(name);
272: }
273:
274: /**
275: * Fills the file and directory maps with resources read from the archive.
276: *
277: * @param archive the archive to scan.
278: * @param encoding encoding used to encode file names inside the archive.
279: * @param fileEntries Map (name to resource) of non-directory
280: * resources found inside the archive.
281: * @param matchFileEntries Map (name to resource) of non-directory
282: * resources found inside the archive that matched all include
283: * patterns and didn't match any exclude patterns.
284: * @param dirEntries Map (name to resource) of directory
285: * resources found inside the archive.
286: * @param matchDirEntries Map (name to resource) of directory
287: * resources found inside the archive that matched all include
288: * patterns and didn't match any exclude patterns.
289: */
290: protected abstract void fillMapsFromArchive(Resource archive,
291: String encoding, Map fileEntries, Map matchFileEntries,
292: Map dirEntries, Map matchDirEntries);
293:
294: /**
295: * if the datetime of the archive did not change since
296: * lastScannedResource was initialized returns immediately else if
297: * the archive has not been scanned yet, then all the zip entries
298: * are put into the appropriate tables.
299: */
300: private void scanme() {
301: //do not use a FileResource b/c it pulls File info from the filesystem:
302: Resource this resource = new Resource(src.getName(), src
303: .isExists(), src.getLastModified());
304: // spare scanning again and again
305: if (lastScannedResource != null
306: && lastScannedResource.getName().equals(
307: this resource.getName())
308: && lastScannedResource.getLastModified() == this resource
309: .getLastModified()) {
310: return;
311: }
312: init();
313:
314: fileEntries.clear();
315: dirEntries.clear();
316: matchFileEntries.clear();
317: matchDirEntries.clear();
318: fillMapsFromArchive(src, encoding, fileEntries,
319: matchFileEntries, dirEntries, matchDirEntries);
320:
321: // record data about the last scanned resource
322: lastScannedResource = this resource;
323: }
324:
325: /**
326: * Remove trailing slash if present.
327: * @param s the file name to trim.
328: * @return the trimed file name.
329: */
330: protected static final String trimSeparator(String s) {
331: return s.endsWith("/") ? s.substring(0, s.length() - 1) : s;
332: }
333:
334: }
|