Source Code Cross Referenced for DirectoryGenerator.java in  » Web-Framework » cocoon » org » apache » cocoon » generation » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Web Framework » cocoon » org.apache.cocoon.generation 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:        package org.apache.cocoon.generation;
018:
019:        import org.apache.avalon.framework.parameters.Parameters;
020:        import org.apache.cocoon.ProcessingException;
021:        import org.apache.cocoon.ResourceNotFoundException;
022:        import org.apache.cocoon.caching.CacheableProcessingComponent;
023:        import org.apache.cocoon.components.source.SourceUtil;
024:        import org.apache.cocoon.environment.SourceResolver;
025:        import org.apache.excalibur.source.Source;
026:        import org.apache.excalibur.source.SourceException;
027:        import org.apache.excalibur.source.SourceValidity;
028:        import org.apache.regexp.RE;
029:        import org.apache.regexp.RESyntaxException;
030:        import org.xml.sax.SAXException;
031:        import org.xml.sax.helpers.AttributesImpl;
032:
033:        import java.io.File;
034:        import java.io.IOException;
035:        import java.io.Serializable;
036:        import java.net.URL;
037:        import java.text.SimpleDateFormat;
038:        import java.util.ArrayList;
039:        import java.util.Date;
040:        import java.util.List;
041:        import java.util.Map;
042:        import java.util.Stack;
043:        import java.util.Arrays;
044:        import java.util.Comparator;
045:
046:        /**
047:         * @cocoon.sitemap.component.documentation
048:         * Generates an XML directory listing.
049:         * A more general approach is implemented by the TraversableGenerator (src/blocks/repository/java/org/apache/cocoon/generation/TraversableGenerator.java)
050:         * 
051:         * @cocoon.sitemap.component.name   directory
052:         * @cocoon.sitemap.component.label  content
053:         * @cocoon.sitemap.component.logger sitemap.generator.directory
054:         * @cocoon.sitemap.component.documentation.caching
055:         *               Uses the last modification date of the directory and the contained files
056:         * 
057:         * @cocoon.sitemap.component.pooling.max  16
058:         *
059:         * @version $Id: DirectoryGenerator.java 433543 2006-08-22 06:22:54Z crossley $
060:         */
061:        public class DirectoryGenerator extends ServiceableGenerator implements 
062:                CacheableProcessingComponent {
063:
064:            /** Constant for the file protocol. */
065:            private static final String FILE = "file:";
066:
067:            /** The URI of the namespace of this generator. */
068:            protected static final String URI = "http://apache.org/cocoon/directory/2.0";
069:
070:            /** The namespace prefix for this namespace. */
071:            protected static final String PREFIX = "dir";
072:
073:            /* Node and attribute names */
074:            protected static final String DIR_NODE_NAME = "directory";
075:            protected static final String FILE_NODE_NAME = "file";
076:
077:            protected static final String FILENAME_ATTR_NAME = "name";
078:            protected static final String LASTMOD_ATTR_NAME = "lastModified";
079:            protected static final String DATE_ATTR_NAME = "date";
080:            protected static final String SIZE_ATTR_NAME = "size";
081:
082:            /** The validity that is being built */
083:            protected DirValidity validity;
084:            /** Convenience object, so we don't need to create an AttributesImpl for every element. */
085:            protected AttributesImpl attributes;
086:
087:            /**
088:             * The cache key needs to be generated for the configuration of this
089:             * generator, so storing the parameters for generateKey().
090:             * Using the member variables after setup() would not work I guess. I don't
091:             * know a way from the regular expressions back to the pattern or at least
092:             * a useful string.
093:             */
094:            protected List cacheKeyParList;
095:
096:            /** The depth parameter determines how deep the DirectoryGenerator should delve. */
097:            protected int depth;
098:            /**
099:             * The dateFormatter determines into which date format the lastModified
100:             * time should be converted.
101:             * FIXME: SimpleDateFormat is not supported by all locales!
102:             */
103:            protected SimpleDateFormat dateFormatter;
104:            /** The delay between checks on updates to the filesystem. */
105:            protected long refreshDelay;
106:            /**
107:             * The sort parameter determines by which attribute the content of one
108:             * directory should be sorted. Possible values are "name", "size", "lastmodified"
109:             * and "directory", where "directory" is the same as "name", except that
110:             * directory entries are listed first.
111:             */
112:            protected String sort;
113:            /** The reverse parameter reverses the sort order. <code>false</code> is default. */
114:            protected boolean reverse;
115:            /** The regular expression for the root pattern. */
116:            protected RE rootRE;
117:            /** The regular expression for the include pattern. */
118:            protected RE includeRE;
119:            /** The regular expression for the exclude pattern. */
120:            protected RE excludeRE;
121:            /**
122:             * This is only set to true for the requested directory specified by the
123:             * <code>src</code> attribute on the generator's configuration.
124:             */
125:            protected boolean isRequestedDirectory;
126:
127:            /** The source object for the directory. */
128:            protected Source directorySource;
129:
130:            /**
131:             * Set the request parameters. Must be called before the generate method.
132:             *
133:             * @param resolver     the SourceResolver object
134:             * @param objectModel  a <code>Map</code> containing model object
135:             * @param src          the directory to be XMLized specified as src attribute on &lt;map:generate/>
136:             * @param par          configuration parameters
137:             */
138:            public void setup(SourceResolver resolver, Map objectModel,
139:                    String src, Parameters par) throws ProcessingException,
140:                    SAXException, IOException {
141:                if (src == null) {
142:                    throw new ProcessingException(
143:                            "No src attribute pointing to a directory to be XMLized specified.");
144:                }
145:                super .setup(resolver, objectModel, src, par);
146:
147:                try {
148:                    this .directorySource = this .resolver.resolveURI(src);
149:                } catch (SourceException se) {
150:                    throw SourceUtil.handle(se);
151:                }
152:
153:                this .cacheKeyParList = new ArrayList();
154:                this .cacheKeyParList.add(this .directorySource.getURI());
155:
156:                this .depth = par.getParameterAsInteger("depth", 1);
157:                this .cacheKeyParList.add(String.valueOf(this .depth));
158:
159:                String dateFormatString = par.getParameter("dateFormat", null);
160:                this .cacheKeyParList.add(dateFormatString);
161:                if (dateFormatString != null) {
162:                    this .dateFormatter = new SimpleDateFormat(dateFormatString);
163:                } else {
164:                    this .dateFormatter = new SimpleDateFormat();
165:                }
166:
167:                this .sort = par.getParameter("sort", "name");
168:                this .cacheKeyParList.add(this .sort);
169:
170:                this .reverse = par.getParameterAsBoolean("reverse", false);
171:                this .cacheKeyParList.add(String.valueOf(this .reverse));
172:
173:                this .refreshDelay = par.getParameterAsLong("refreshDelay", 1L) * 1000L;
174:                this .cacheKeyParList.add(String.valueOf(this .refreshDelay));
175:
176:                if (this .getLogger().isDebugEnabled()) {
177:                    this .getLogger().debug("depth: " + this .depth);
178:                    this .getLogger().debug(
179:                            "dateFormat: " + this .dateFormatter.toPattern());
180:                    this .getLogger().debug("sort: " + this .sort);
181:                    this .getLogger().debug("reverse: " + this .reverse);
182:                    this .getLogger()
183:                            .debug("refreshDelay: " + this .refreshDelay);
184:                }
185:
186:                String rePattern = null;
187:                try {
188:                    rePattern = par.getParameter("root", null);
189:                    this .cacheKeyParList.add(rePattern);
190:                    this .rootRE = (rePattern == null) ? null
191:                            : new RE(rePattern);
192:                    if (this .getLogger().isDebugEnabled()) {
193:                        this .getLogger().debug("root pattern: " + rePattern);
194:                    }
195:
196:                    rePattern = par.getParameter("include", null);
197:                    this .cacheKeyParList.add(rePattern);
198:                    this .includeRE = (rePattern == null) ? null : new RE(
199:                            rePattern);
200:                    if (this .getLogger().isDebugEnabled()) {
201:                        this .getLogger().debug("include pattern: " + rePattern);
202:                    }
203:
204:                    rePattern = par.getParameter("exclude", null);
205:                    this .cacheKeyParList.add(rePattern);
206:                    this .excludeRE = (rePattern == null) ? null : new RE(
207:                            rePattern);
208:                    if (this .getLogger().isDebugEnabled()) {
209:                        this .getLogger().debug("exclude pattern: " + rePattern);
210:                    }
211:                } catch (RESyntaxException rese) {
212:                    throw new ProcessingException(
213:                            "Syntax error in regexp pattern '" + rePattern
214:                                    + "'", rese);
215:                }
216:
217:                this .isRequestedDirectory = false;
218:                this .attributes = new AttributesImpl();
219:            }
220:
221:            /* (non-Javadoc)
222:             * @see org.apache.cocoon.caching.CacheableProcessingComponent#getKey()
223:             */
224:            public Serializable getKey() {
225:                StringBuffer buffer = new StringBuffer();
226:                int len = this .cacheKeyParList.size();
227:                for (int i = 0; i < len; i++) {
228:                    buffer.append((String) this .cacheKeyParList.get(i) + ":");
229:                }
230:                return buffer.toString();
231:            }
232:
233:            /**
234:             * Gets the source validity, using a deferred validity object. The validity
235:             * is initially empty since the files that define it are not known before
236:             * generation has occured. So the returned object is kept by the generator
237:             * and filled with each of the files that are traversed.
238:             * 
239:             * @see DirectoryGenerator.DirValidity
240:             */
241:            public SourceValidity getValidity() {
242:                if (this .validity == null) {
243:                    this .validity = new DirValidity(this .refreshDelay);
244:                }
245:                return this .validity;
246:            }
247:
248:            /**
249:             * Generate XML data.
250:             * 
251:             * @throws SAXException  if an error occurs while outputting the document
252:             * @throws ProcessingException  if the requsted URI isn't a directory on the local filesystem
253:             */
254:            public void generate() throws SAXException, ProcessingException {
255:                try {
256:                    String systemId = this .directorySource.getURI();
257:                    if (!systemId.startsWith(FILE)) {
258:                        throw new ResourceNotFoundException(systemId
259:                                + " does not denote a directory");
260:                    }
261:                    // This relies on systemId being of the form "file://..."
262:                    File directoryFile = new File(new URL(systemId).getFile());
263:                    if (!directoryFile.isDirectory()) {
264:                        throw new ResourceNotFoundException(super .source
265:                                + " is not a directory.");
266:                    }
267:
268:                    this .contentHandler.startDocument();
269:                    this .contentHandler.startPrefixMapping(PREFIX, URI);
270:
271:                    Stack ancestors = getAncestors(directoryFile);
272:                    addAncestorPath(directoryFile, ancestors);
273:
274:                    this .contentHandler.endPrefixMapping(PREFIX);
275:                    this .contentHandler.endDocument();
276:                } catch (IOException ioe) {
277:                    throw new ResourceNotFoundException(
278:                            "Could not read directory " + super .source, ioe);
279:                }
280:            }
281:
282:            /**
283:             * Creates a stack containing the ancestors of File up to specified directory.
284:             * 
285:             * @param path the File whose ancestors shall be retrieved
286:             * @return a Stack containing the ancestors.
287:             */
288:            protected Stack getAncestors(File path) {
289:                File parent = path;
290:                Stack ancestors = new Stack();
291:
292:                while ((parent != null) && !isRoot(parent)) {
293:                    parent = parent.getParentFile();
294:                    if (parent != null) {
295:                        ancestors.push(parent);
296:                    } else {
297:                        // no ancestor matched the root pattern
298:                        ancestors.clear();
299:                    }
300:                }
301:
302:                return ancestors;
303:            }
304:
305:            /**
306:             * Adds recursively the path from the directory matched by the root pattern
307:             * down to the requested directory.
308:             * 
309:             * @param path       the requested directory.
310:             * @param ancestors  the stack of the ancestors.
311:             * @throws SAXException
312:             */
313:            protected void addAncestorPath(File path, Stack ancestors)
314:                    throws SAXException {
315:                if (ancestors.empty()) {
316:                    this .isRequestedDirectory = true;
317:                    addPath(path, depth);
318:                } else {
319:                    startNode(DIR_NODE_NAME, (File) ancestors.pop());
320:                    addAncestorPath(path, ancestors);
321:                    endNode(DIR_NODE_NAME);
322:                }
323:            }
324:
325:            /**
326:             * Adds a single node to the generated document. If the path is a
327:             * directory, and depth is greater than zero, then recursive calls
328:             * are made to add nodes for the directory's children.
329:             * 
330:             * @param path   the file/directory to process
331:             * @param depth  how deep to scan the directory
332:             * @throws SAXException  if an error occurs while constructing nodes
333:             */
334:            protected void addPath(File path, int depth) throws SAXException {
335:                if (path.isDirectory()) {
336:                    startNode(DIR_NODE_NAME, path);
337:                    if (depth > 0) {
338:                        File contents[] = path.listFiles();
339:
340:                        if (sort.equals("name")) {
341:                            Arrays.sort(contents, new Comparator() {
342:                                public int compare(Object o1, Object o2) {
343:                                    if (reverse) {
344:                                        return ((File) o2).getName().compareTo(
345:                                                ((File) o1).getName());
346:                                    }
347:                                    return ((File) o1).getName().compareTo(
348:                                            ((File) o2).getName());
349:                                }
350:                            });
351:                        } else if (sort.equals("size")) {
352:                            Arrays.sort(contents, new Comparator() {
353:                                public int compare(Object o1, Object o2) {
354:                                    if (reverse) {
355:                                        return new Long(((File) o2).length())
356:                                                .compareTo(new Long(((File) o1)
357:                                                        .length()));
358:                                    }
359:                                    return new Long(((File) o1).length())
360:                                            .compareTo(new Long(((File) o2)
361:                                                    .length()));
362:                                }
363:                            });
364:                        } else if (sort.equals("lastmodified")) {
365:                            Arrays.sort(contents, new Comparator() {
366:                                public int compare(Object o1, Object o2) {
367:                                    if (reverse) {
368:                                        return new Long(((File) o2)
369:                                                .lastModified())
370:                                                .compareTo(new Long(((File) o1)
371:                                                        .lastModified()));
372:                                    }
373:                                    return new Long(((File) o1).lastModified())
374:                                            .compareTo(new Long(((File) o2)
375:                                                    .lastModified()));
376:                                }
377:                            });
378:                        } else if (sort.equals("directory")) {
379:                            Arrays.sort(contents, new Comparator() {
380:                                public int compare(Object o1, Object o2) {
381:                                    File f1 = (File) o1;
382:                                    File f2 = (File) o2;
383:
384:                                    if (reverse) {
385:                                        if (f2.isDirectory() && f1.isFile())
386:                                            return -1;
387:                                        if (f2.isFile() && f1.isDirectory())
388:                                            return 1;
389:                                        return f2.getName().compareTo(
390:                                                f1.getName());
391:                                    }
392:                                    if (f2.isDirectory() && f1.isFile())
393:                                        return 1;
394:                                    if (f2.isFile() && f1.isDirectory())
395:                                        return -1;
396:                                    return f1.getName().compareTo(f2.getName());
397:                                }
398:                            });
399:                        }
400:
401:                        for (int i = 0; i < contents.length; i++) {
402:                            if (isIncluded(contents[i])
403:                                    && !isExcluded(contents[i])) {
404:                                addPath(contents[i], depth - 1);
405:                            }
406:                        }
407:                    }
408:                    endNode(DIR_NODE_NAME);
409:                } else {
410:                    if (isIncluded(path) && !isExcluded(path)) {
411:                        startNode(FILE_NODE_NAME, path);
412:                        endNode(FILE_NODE_NAME);
413:                    }
414:                }
415:            }
416:
417:            /**
418:             * Begins a named node and calls setNodeAttributes to set its attributes.
419:             * 
420:             * @param nodeName  the name of the new node
421:             * @param path      the file/directory to use when setting attributes
422:             * @throws SAXException  if an error occurs while creating the node
423:             */
424:            protected void startNode(String nodeName, File path)
425:                    throws SAXException {
426:                if (this .validity != null) {
427:                    this .validity.addFile(path);
428:                }
429:                setNodeAttributes(path);
430:                super .contentHandler.startElement(URI, nodeName, PREFIX + ':'
431:                        + nodeName, attributes);
432:            }
433:
434:            /**
435:             * Sets the attributes for a given path. The default method sets attributes
436:             * for the name of thefile/directory and for the last modification time
437:             * of the path.
438:             * 
439:             * @param path  the file/directory to use when setting attributes
440:             * @throws SAXException  if an error occurs while setting the attributes
441:             */
442:            protected void setNodeAttributes(File path) throws SAXException {
443:                long lastModified = path.lastModified();
444:                attributes.clear();
445:                attributes.addAttribute("", FILENAME_ATTR_NAME,
446:                        FILENAME_ATTR_NAME, "CDATA", path.getName());
447:                attributes.addAttribute("", LASTMOD_ATTR_NAME,
448:                        LASTMOD_ATTR_NAME, "CDATA", Long.toString(path
449:                                .lastModified()));
450:                attributes.addAttribute("", DATE_ATTR_NAME, DATE_ATTR_NAME,
451:                        "CDATA", dateFormatter.format(new Date(lastModified)));
452:                attributes.addAttribute("", SIZE_ATTR_NAME, SIZE_ATTR_NAME,
453:                        "CDATA", Long.toString(path.length()));
454:                if (this .isRequestedDirectory) {
455:                    attributes.addAttribute("", "sort", "sort", "CDATA",
456:                            this .sort);
457:                    attributes.addAttribute("", "reverse", "reverse", "CDATA",
458:                            String.valueOf(this .reverse));
459:                    attributes.addAttribute("", "requested", "requested",
460:                            "CDATA", "true");
461:                    this .isRequestedDirectory = false;
462:                }
463:            }
464:
465:            /**
466:             * Ends the named node.
467:             * 
468:             * @param nodeName  the name of the new node
469:             * @throws SAXException  if an error occurs while closing the node
470:             */
471:            protected void endNode(String nodeName) throws SAXException {
472:                super .contentHandler.endElement(URI, nodeName, PREFIX + ':'
473:                        + nodeName);
474:            }
475:
476:            /**
477:             * Determines if a given File is the defined root.
478:             * 
479:             * @param path  the File to check
480:             * @return true if the File is the root or the root pattern is not set,
481:             *         false otherwise.
482:             */
483:            protected boolean isRoot(File path) {
484:                return (this .rootRE == null) ? true : this .rootRE.match(path
485:                        .getName());
486:            }
487:
488:            /**
489:             * Determines if a given File shall be visible.
490:             * 
491:             * @param path  the File to check
492:             * @return true if the File shall be visible or the include Pattern is <code>null</code>,
493:             *         false otherwise.
494:             */
495:            protected boolean isIncluded(File path) {
496:                return (this .includeRE == null) ? true : this .includeRE
497:                        .match(path.getName());
498:            }
499:
500:            /**
501:             * Determines if a given File shall be excluded from viewing.
502:             * 
503:             * @param path  the File to check
504:             * @return false if the given File shall not be excluded or the exclude Pattern is <code>null</code>,
505:             *         true otherwise.
506:             */
507:            protected boolean isExcluded(File path) {
508:                return (this .excludeRE == null) ? false : this .excludeRE
509:                        .match(path.getName());
510:            }
511:
512:            /**
513:             * Recycle resources
514:             */
515:            public void recycle() {
516:                if (this .resolver != null) {
517:                    this .resolver.release(this .directorySource);
518:                    this .directorySource = null;
519:                }
520:                this .cacheKeyParList = null;
521:                this .attributes = null;
522:                this .dateFormatter = null;
523:                this .rootRE = null;
524:                this .includeRE = null;
525:                this .excludeRE = null;
526:                this .validity = null;
527:                super .recycle();
528:            }
529:
530:            /** Specific validity class, that holds all files that have been generated */
531:            public static class DirValidity implements  SourceValidity {
532:
533:                private long expiry;
534:                private long delay;
535:                List files = new ArrayList();
536:                List fileDates = new ArrayList();
537:
538:                public DirValidity(long delay) {
539:                    expiry = System.currentTimeMillis() + delay;
540:                    this .delay = delay;
541:                }
542:
543:                public int isValid() {
544:                    if (System.currentTimeMillis() <= expiry) {
545:                        return SourceValidity.VALID;
546:                    }
547:
548:                    int len = files.size();
549:                    for (int i = 0; i < len; i++) {
550:                        File f = (File) files.get(i);
551:                        if (!f.exists()) {
552:                            return SourceValidity.INVALID; // File was removed
553:                        }
554:
555:                        long oldDate = ((Long) fileDates.get(i)).longValue();
556:                        long newDate = f.lastModified();
557:
558:                        if (oldDate != newDate) {
559:                            // File's last modified date has changed since last check
560:                            // NOTE: this occurs on directories as well when a file is added
561:                            return SourceValidity.INVALID;
562:                        }
563:                    }
564:
565:                    // all content is up to date: update the expiry date
566:                    expiry = System.currentTimeMillis() + delay;
567:                    return SourceValidity.VALID;
568:                }
569:
570:                public int isValid(SourceValidity newValidity) {
571:                    return isValid();
572:                }
573:
574:                public void addFile(File f) {
575:                    files.add(f);
576:                    fileDates.add(new Long(f.lastModified()));
577:                }
578:            }
579:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.