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.bean;
018:
019: import org.apache.avalon.framework.component.Component;
020: import org.apache.cocoon.Constants;
021: import org.apache.cocoon.ProcessingException;
022: import org.apache.cocoon.bean.helpers.Crawler;
023: import org.apache.cocoon.bean.helpers.DelayedOutputStream;
024: import org.apache.cocoon.components.notification.SimpleNotifyingBean;
025: import org.apache.cocoon.components.notification.Notifier;
026: import org.apache.cocoon.components.notification.DefaultNotifyingBuilder;
027: import org.apache.cocoon.components.notification.Notifying;
028: import org.apache.cocoon.util.WildcardMatcherHelper;
029: import org.apache.commons.lang.SystemUtils;
030:
031: import org.apache.excalibur.source.ModifiableSource;
032: import org.apache.excalibur.source.SourceResolver;
033: import org.apache.excalibur.source.Source;
034: import org.apache.excalibur.source.SourceNotFoundException;
035: import org.apache.excalibur.source.SourceUtil;
036:
037: import java.io.BufferedReader;
038: import java.io.InputStream;
039: import java.io.InputStreamReader;
040: import java.io.IOException;
041: import java.io.OutputStream;
042: import java.io.OutputStreamWriter;
043: import java.io.PrintStream;
044: import java.io.PrintWriter;
045: import java.security.MessageDigest;
046: import java.security.NoSuchAlgorithmException;
047:
048: import java.util.ArrayList;
049: import java.util.HashMap;
050: import java.util.Iterator;
051: import java.util.List;
052: import java.util.Map;
053: import java.util.TreeMap;
054:
055: /**
056: * <p>The Cocoon Bean simplifies usage of the Cocoon object. Allows to create,
057: * configure Cocoon instance and process requests, one by one or multiple
058: * with link traversal.</p>
059: *
060: * <p><b>WARNING:</b> This interface is not stable and could be changed in
061: * backward incompatible way without prior notice.</p>
062:
063: * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
064: * @author <a href="mailto:nicolaken@apache.org">Nicola Ken Barozzi</a>
065: * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
066: * @author <a href="mailto:uv@upaya.co.uk">Upayavira</a>
067: * @version CVS $Id: CocoonBean.java 540711 2007-05-22 19:36:07Z cziegeler $
068: */
069: public class CocoonBean extends CocoonWrapper {
070:
071: // User Supplied Parameters
072: private boolean followLinks = true;
073: private boolean precompileOnly = false;
074: private boolean confirmExtension = true;
075: private String defaultFilename = Constants.INDEX_URI;
076: private boolean brokenLinkGenerate = false;
077: private String brokenLinkExtension = "";
078: private List excludePatterns = new ArrayList();
079: private List includePatterns = new ArrayList();
080: private List includeLinkExtensions = null;
081:
082: // Internal Objects
083: private boolean initialized;
084: private List listeners = new ArrayList();
085: private boolean verbose;
086: SourceResolver sourceResolver;
087:
088: private Crawler crawler;
089: private String checksumsURI = null;
090: private Map checksums;
091:
092: public CocoonBean() {
093: this .crawler = new Crawler();
094: }
095:
096: //
097: // INITIALISATION METHOD
098: //
099:
100: public void initialize() throws Exception {
101: if (this .initialized == false) {
102: super .initialize();
103:
104: this .sourceResolver = (SourceResolver) this
105: .getComponentManager().lookup(SourceResolver.ROLE);
106:
107: this .initialized = true;
108: }
109: }
110:
111: protected void finalize() throws Throwable {
112: this .dispose();
113: super .finalize();
114: }
115:
116: //
117: // GETTERS AND SETTERS FOR CONFIGURATION PROPERTIES
118: //
119:
120: public void setFollowLinks(boolean follow) {
121: this .followLinks = follow;
122: }
123:
124: public void setConfirmExtensions(boolean confirmExtension) {
125: this .confirmExtension = confirmExtension;
126: }
127:
128: public void setPrecompileOnly(boolean precompileOnly) {
129: this .precompileOnly = precompileOnly;
130: }
131:
132: public boolean isPrecompileOnly() {
133: return this .precompileOnly;
134: }
135:
136: public void setVerbose(boolean verbose) {
137: this .verbose = verbose;
138: }
139:
140: public void setDefaultFilename(String filename) {
141: this .defaultFilename = filename;
142: }
143:
144: public void setBrokenLinkGenerate(boolean brokenLinkGenerate) {
145: this .brokenLinkGenerate = brokenLinkGenerate;
146: }
147:
148: public void setBrokenLinkExtension(String brokenLinkExtension) {
149: this .brokenLinkExtension = brokenLinkExtension;
150: }
151:
152: public void setChecksumURI(String uri) {
153: this .checksumsURI = uri;
154: }
155:
156: public boolean followLinks() {
157: return this .followLinks;
158: }
159:
160: public boolean confirmExtensions() {
161: return this .confirmExtension;
162: }
163:
164: /**
165: * Adds a target for processing
166: *
167: * @param type Type of target - append, replace, insert.
168: * @param root
169: * @param sourceURI URI of the starting page
170: * @param destURI URI specifying destination for the generated pages.
171: * @throws IllegalArgumentException if destURI is missing
172: */
173: public void addTarget(String type, String root, String sourceURI,
174: String destURI) throws IllegalArgumentException {
175: Target target = new Target(type, root, sourceURI, destURI);
176: target.setDefaultFilename(this .defaultFilename);
177: target.setFollowLinks(this .followLinks);
178: target.setConfirmExtension(this .confirmExtension);
179: target.setLogger(this .logger);
180: this .crawler.addTarget(target);
181: }
182:
183: public void addTarget(String type, String sourceURI, String destURI)
184: throws IllegalArgumentException {
185: Target target = new Target(type, sourceURI, destURI);
186: target.setDefaultFilename(this .defaultFilename);
187: target.setFollowLinks(this .followLinks);
188: target.setConfirmExtension(this .confirmExtension);
189: target.setLogger(this .logger);
190: this .crawler.addTarget(target);
191: }
192:
193: public void addTarget(String sourceURI, String destURI)
194: throws IllegalArgumentException {
195: Target target = new Target(sourceURI, destURI);
196: target.setDefaultFilename(this .defaultFilename);
197: target.setFollowLinks(this .followLinks);
198: target.setConfirmExtension(this .confirmExtension);
199: target.setLogger(this .logger);
200: this .crawler.addTarget(target);
201: }
202:
203: public void addTargets(List uris, String destURI)
204: throws IllegalArgumentException {
205: Iterator i = uris.iterator();
206: while (i.hasNext()) {
207: Target target = new Target((String) i.next(), destURI);
208: target.setDefaultFilename(this .defaultFilename);
209: target.setFollowLinks(this .followLinks);
210: target.setConfirmExtension(this .confirmExtension);
211: target.setLogger(this .logger);
212: this .crawler.addTarget(target);
213: }
214: }
215:
216: public void addTarget(String type, String root, String sourceURI,
217: String destURI, boolean followLinks,
218: boolean confirmExtension, String logger)
219: throws IllegalArgumentException {
220:
221: Target target;
222: if (root == null && type == null) {
223: target = new Target(sourceURI, destURI);
224: } else if (root == null) {
225: target = new Target(type, sourceURI, destURI);
226: } else {
227: target = new Target(type, root, sourceURI, destURI);
228: }
229: target.setDefaultFilename(this .defaultFilename);
230: target.setFollowLinks(followLinks);
231: target.setConfirmExtension(confirmExtension);
232: target.setLogger(logger);
233: this .crawler.addTarget(target);
234: }
235:
236: public int getTargetCount() {
237: return this .crawler.getRemainingCount();
238: }
239:
240: public void addExcludePattern(String pattern) {
241: this .excludePatterns.add(pattern);
242: }
243:
244: public void addIncludePattern(String pattern) {
245: this .includePatterns.add(pattern);
246: }
247:
248: public void addIncludeLinkExtension(String extension) {
249: if (this .includeLinkExtensions == null) {
250: this .includeLinkExtensions = new ArrayList();
251: }
252: this .includeLinkExtensions.add(extension);
253: }
254:
255: public void addListener(BeanListener listener) {
256: this .listeners.add(listener);
257: }
258:
259: public void pageGenerated(String sourceURI, String destURI,
260: int pageSize, int linksInPage, int newLinksInPage,
261: int pagesRemaining, int pagesComplete, long timeTaken) {
262: Iterator i = this .listeners.iterator();
263: while (i.hasNext()) {
264: BeanListener l = (BeanListener) i.next();
265: l.pageGenerated(sourceURI, destURI, pageSize, linksInPage,
266: newLinksInPage, pagesRemaining, pagesComplete,
267: timeTaken);
268: }
269: }
270:
271: public void sendMessage(String msg) {
272: Iterator i = this .listeners.iterator();
273: while (i.hasNext()) {
274: BeanListener l = (BeanListener) i.next();
275: l.messageGenerated(msg);
276: }
277: }
278:
279: public void sendWarning(String uri, String warning) {
280: Iterator i = this .listeners.iterator();
281: while (i.hasNext()) {
282: BeanListener l = (BeanListener) i.next();
283: l.warningGenerated(uri, warning);
284: }
285: }
286:
287: public void sendBrokenLinkWarning(String uri, String warning) {
288: Iterator i = this .listeners.iterator();
289: while (i.hasNext()) {
290: BeanListener l = (BeanListener) i.next();
291: l.brokenLinkFound(uri, "", warning, null);
292: }
293: }
294:
295: public void pageSkipped(String uri, String message) {
296: Iterator i = this .listeners.iterator();
297: while (i.hasNext()) {
298: BeanListener l = (BeanListener) i.next();
299: l.pageSkipped(uri, message);
300: }
301: }
302:
303: public void dispose() {
304: if (this .initialized) {
305: if (this .sourceResolver != null) {
306: this .getComponentManager().release(
307: (Component) this .sourceResolver);
308: this .sourceResolver = null;
309: }
310: super .dispose();
311: }
312: }
313:
314: /**
315: * Process the URI list and process them all independently.
316: * @exception Exception if an error occurs
317: */
318: public void process() throws Exception {
319:
320: if (!this .initialized) {
321: this .initialize();
322: }
323:
324: if (this .crawler.getRemainingCount() == 0
325: && !this .precompileOnly) {
326: this .log.info("No targets for to be processed.");
327: return;
328: }
329:
330: if (this .checksumsURI != null) {
331: this .readChecksumFile();
332: }
333:
334: if (this .crawler.getRemainingCount() >= 0) {
335: Iterator iterator = this .crawler.iterator();
336: while (iterator.hasNext()) {
337: Target target = (Target) iterator.next();
338: if (!this .precompileOnly) {
339: this .processTarget(this .crawler, target);
340: }
341: }
342: }
343:
344: if (this .checksumsURI != null) {
345: this .writeChecksumFile();
346: }
347:
348: if (this .log.isInfoEnabled()) {
349: this .log.info(" Memory used: "
350: + (Runtime.getRuntime().totalMemory() - Runtime
351: .getRuntime().freeMemory()));
352: this .log.info(" Processed, Translated & Left: "
353: + this .crawler.getProcessedCount() + ", "
354: + this .crawler.getTranslatedCount() + ", "
355: + this .crawler.getRemainingCount());
356: }
357: }
358:
359: /**
360: * Processes the given Target and return all links.
361: *
362: * If links are to be followed, and extensions checked then the algorithm is as
363: * follows:
364: * <ul>
365: * <li>file name for the URI is generated. URI MIME type is checked for
366: * consistency with the URI and, if the extension is inconsistent
367: * or absent, the file name is changed</li>
368: * <li>the link view of the given URI is called and the file names for linked
369: * resources are generated and stored.</li>
370: * <li>for each link, absolute file name is translated to relative path.</li>
371: * <li>after the complete list of links is translated, the link-translating
372: * view of the resource is called to obtain a link-translated version
373: * of the resource with the given link map</li>
374: * <li>list of absolute URI is returned, for every URI which is not yet
375: * present in list of all translated URIs</li>
376: * </ul>
377: *
378: * If links are to be followed, but extensions are not checked, then the
379: * algorithm will be:
380: * <ul>
381: * <li>The content for the page is generated</li>
382: * <li>Whilst generating, all links are gathered by the LinkGatherer</li>
383: * <li>Gathered links are added to the unprocessed links list, and
384: * processing continues until all processing is complete
385: * </li>
386: * </ul>
387: *
388: * @param target a <code>Target</code> target to process
389: * @exception Exception if an error occurs
390: */
391: private void processTarget(Crawler crawler, Target target)
392: throws Exception {
393:
394: int status = 0;
395:
396: int linkCount = 0;
397: int newLinkCount = 0;
398: int pageSize = 0;
399: long startTimeMillis = System.currentTimeMillis();
400:
401: if (target.confirmExtensions()) {
402: if (!crawler.hasTranslatedLink(target)) {
403: final String mimeType = this .getType(target
404: .getDeparameterizedSourceURI(), target
405: .getParameters());
406: target.setMimeType(mimeType);
407: crawler.addTranslatedLink(target);
408: }
409: }
410:
411: // IS THIS STILL NEEDED?
412: //if ("".equals(destinationURI)) {
413: // return new ArrayList();
414: //}
415:
416: // Process links
417: final HashMap translatedLinks = new HashMap();
418: if (target.followLinks() && target.confirmExtensions()
419: && this .isCrawlablePage(target)) {
420: final Iterator i = this .getLinks(
421: target.getDeparameterizedSourceURI(),
422: target.getParameters()).iterator();
423:
424: while (i.hasNext()) {
425: String linkURI = (String) i.next();
426: Target linkTarget = target.getDerivedTarget(linkURI);
427:
428: if (linkTarget == null) {
429: this .pageSkipped(linkURI,
430: "link does not share same root as parent");
431: continue;
432: }
433:
434: if (!this .isIncluded(linkTarget.getSourceURI())) {
435: this .pageSkipped(linkTarget.getSourceURI(),
436: "matched include/exclude rules");
437: continue;
438: }
439:
440: if (!crawler.hasTranslatedLink(linkTarget)) {
441: try {
442: final String mimeType = this .getType(linkTarget
443: .getDeparameterizedSourceURI(),
444: linkTarget.getParameters());
445: linkTarget.setMimeType(mimeType);
446: crawler.addTranslatedLink(linkTarget);
447: this .log.info(" Link translated: "
448: + linkTarget.getSourceURI());
449: if (crawler.addTarget(linkTarget)) {
450: newLinkCount++;
451: }
452: } catch (ProcessingException pe) {
453: this .sendBrokenLinkWarning(linkTarget
454: .getSourceURI(), pe.getMessage());
455: if (this .brokenLinkGenerate) {
456: if (crawler.addTarget(linkTarget)) {
457: newLinkCount++;
458: }
459: }
460: }
461: } else {
462: String originalURI = linkTarget
463: .getOriginalSourceURI();
464: linkTarget = crawler.getTranslatedLink(linkTarget);
465: linkTarget.setOriginalURI(originalURI);
466: }
467:
468: translatedLinks.put(linkTarget.getOriginalSourceURI(),
469: linkTarget.getTranslatedURI(target.getPath()));
470: }
471:
472: linkCount = translatedLinks.size();
473: }
474:
475: try {
476: // Process URI
477: DelayedOutputStream output = new DelayedOutputStream();
478: try {
479: List gatheredLinks;
480: if (!target.confirmExtensions() && target.followLinks()
481: && this .isCrawlablePage(target)) {
482: gatheredLinks = new ArrayList();
483: } else {
484: gatheredLinks = null;
485: }
486:
487: final TreeMap headers = new TreeMap();
488: headers.put("user-agent", this .userAgent);
489: headers.put("accept", this .accept);
490:
491: status = this .getPage(target
492: .getDeparameterizedSourceURI(), this
493: .getLastModified(target), target
494: .getParameters(), headers, target
495: .confirmExtensions() ? translatedLinks : null,
496: gatheredLinks, output);
497:
498: if (status >= 400) {
499: throw new ProcessingException(
500: "Resource not found: " + status);
501: }
502:
503: if (gatheredLinks != null) {
504: for (Iterator it = gatheredLinks.iterator(); it
505: .hasNext();) {
506: String linkURI = (String) it.next();
507: Target linkTarget = target
508: .getDerivedTarget(linkURI);
509:
510: if (linkTarget == null) {
511: this
512: .pageSkipped(linkURI,
513: "link does not share same root as parent");
514: continue;
515: }
516:
517: if (!this .isIncluded(linkTarget.getSourceURI())) {
518: this .pageSkipped(linkTarget.getSourceURI(),
519: "matched include/exclude rules");
520: continue;
521: }
522: if (crawler.addTarget(linkTarget)) {
523: newLinkCount++;
524: }
525: }
526: linkCount = gatheredLinks.size();
527: }
528:
529: } catch (ProcessingException pe) {
530: output.close();
531: output = null;
532: this .resourceUnavailable(target);
533: this .sendBrokenLinkWarning(target.getSourceURI(),
534: DefaultNotifyingBuilder.getRootCause(pe)
535: .getMessage());
536: } finally {
537: if (output != null && status != -1) {
538:
539: ModifiableSource source = this .getSource(target);
540: try {
541: pageSize = output.size();
542:
543: if (this .checksumsURI == null
544: || !this .isSameContent(output, target)) {
545: OutputStream stream = source
546: .getOutputStream();
547: output.setFileOutputStream(stream);
548: output.flush();
549: output.close();
550: this .pageGenerated(target.getSourceURI(),
551: target.getAuthlessDestURI(),
552: pageSize, linkCount, newLinkCount,
553: crawler.getRemainingCount(),
554: crawler.getProcessedCount(), System
555: .currentTimeMillis()
556: - startTimeMillis);
557: } else {
558: output.close();
559: this .pageSkipped(target.getSourceURI(),
560: "Page not changed");
561: }
562: } catch (IOException ioex) {
563: this .log.warn(ioex.toString());
564: } finally {
565: this .releaseSource(source);
566: }
567: }
568: }
569: } catch (Exception rnfe) {
570: this .log.warn("Could not process URI: "
571: + target.getSourceURI());
572: rnfe.printStackTrace();
573: this .sendBrokenLinkWarning(target.getSourceURI(),
574: "URI not found: " + rnfe.getMessage());
575: }
576: }
577:
578: /**
579: * Generate a <code>resourceUnavailable</code> message.
580: *
581: * @param target being unavailable
582: * @exception IOException if an error occurs
583: */
584: private void resourceUnavailable(Target target) throws IOException,
585: ProcessingException {
586: if (this .brokenLinkGenerate) {
587: //Why decode this URI now?
588: //String brokenFile = NetUtils.decodePath(destinationURI);
589:
590: if (this .brokenLinkExtension != null) {
591: target.setExtraExtension(this .brokenLinkExtension);
592: }
593: SimpleNotifyingBean n = new SimpleNotifyingBean(this );
594: n.setType("resource-not-found");
595: n.setTitle("Resource not Found");
596: n.setSource("Cocoon commandline (Main.java)");
597: n.setMessage("Page Not Available.");
598: n
599: .setDescription("The requested resource couldn't be found.");
600: n.addExtraDescription(Notifying.EXTRA_REQUESTURI, target
601: .getSourceURI());
602: n
603: .addExtraDescription("missing-file", target
604: .getSourceURI());
605:
606: ModifiableSource source = this .getSource(target);
607: OutputStream stream = null;
608: PrintStream out = null;
609: try {
610: stream = source.getOutputStream();
611: out = new PrintStream(stream);
612: Notifier.notify(n, out, "text/html");
613: } finally {
614: if (out != null)
615: out.close();
616: if (stream != null)
617: stream.close();
618: this .releaseSource(source);
619: }
620: }
621: }
622:
623: public ModifiableSource getSource(Target target)
624: throws IOException, ProcessingException {
625: final String finalDestinationURI = target.getDestinationURI();
626: Source src = this .sourceResolver
627: .resolveURI(finalDestinationURI);
628: if (!(src instanceof ModifiableSource)) {
629: this .sourceResolver.release(src);
630: throw new ProcessingException("Source is not Modifiable: "
631: + finalDestinationURI);
632: }
633: return (ModifiableSource) src;
634: }
635:
636: public long getLastModified(Target target) throws IOException,
637: ProcessingException {
638: Source src = this .getSource(target);
639: long lastModified = src.getLastModified();
640: this .releaseSource(src);
641: return lastModified;
642: }
643:
644: public void releaseSource(Source source) {
645: this .sourceResolver.release(source);
646: }
647:
648: private boolean isIncluded(String uri) {
649: boolean included;
650: Iterator i;
651: HashMap map = new HashMap();
652:
653: if (this .includePatterns.size() == 0) {
654: included = true;
655: } else {
656: included = false;
657: i = this .includePatterns.iterator();
658: while (i.hasNext()) {
659: final String pattern = (String) i.next();
660: if (WildcardMatcherHelper.match(pattern, uri) != null) {
661: included = true;
662: break;
663: }
664: }
665: }
666: if (this .excludePatterns.size() != 0) {
667: i = this .excludePatterns.iterator();
668: while (i.hasNext()) {
669: final String pattern = (String) i.next();
670: if (WildcardMatcherHelper.match(pattern, uri) != null) {
671: included = false;
672: break;
673: }
674: }
675: }
676: return included;
677: }
678:
679: private boolean isCrawlablePage(Target target) {
680: if (this .includeLinkExtensions == null) {
681: return true;
682: } else {
683: return this .includeLinkExtensions.contains(target
684: .getExtension());
685: }
686: }
687:
688: /* NB. This is a temporary solution - it may well be replaced by storing the checksum info
689: * in the XML 'report' file, along with details of what pages were created, etc.
690: */
691: private void readChecksumFile() throws Exception {
692: this .checksums = new HashMap();
693: InputStream is = null;
694: InputStreamReader isr = null;
695: BufferedReader reader = null;
696: try {
697: Source checksumSource = this .sourceResolver
698: .resolveURI(this .checksumsURI);
699: is = checksumSource.getInputStream();
700: isr = new InputStreamReader(is);
701: reader = new BufferedReader(isr);
702: String line;
703: int lineNo = 0;
704: while ((line = reader.readLine()) != null) {
705: lineNo++;
706: if (line.trim().startsWith("#")
707: || line.trim().length() == 0) {
708: continue;
709: }
710: if (line.indexOf("\t") == -1) {
711: throw new ProcessingException(
712: "Missing tab at line " + lineNo + " of "
713: + this .checksumsURI);
714: }
715: String filename = line.substring(0, line.indexOf("\t"));
716: String checksum = line
717: .substring(line.indexOf("\t") + 1);
718: this .checksums.put(filename, checksum);
719: }
720: reader.close();
721: } catch (SourceNotFoundException e) {
722: // return leaving checksums map empty
723: } finally {
724: if (reader != null)
725: reader.close();
726: if (isr != null)
727: isr.close();
728: if (is != null)
729: is.close();
730: }
731: }
732:
733: private void writeChecksumFile() throws Exception {
734: Source checksumSource = this .sourceResolver
735: .resolveURI(this .checksumsURI);
736: if (!(checksumSource instanceof ModifiableSource)) {
737: throw new ProcessingException(
738: "Checksum file is not Modifiable:" + checksumSource);
739: }
740: ModifiableSource source = (ModifiableSource) checksumSource;
741: PrintWriter writer = new PrintWriter(new OutputStreamWriter(
742: source.getOutputStream()));
743: Iterator i = this .checksums.keySet().iterator();
744: while (i.hasNext()) {
745: String key = (String) i.next();
746: String checksum = (String) this .checksums.get(key);
747: writer.println(key + "\t" + checksum);
748: }
749: writer.close();
750: }
751:
752: private boolean isSameContent(DelayedOutputStream stream,
753: Target target) {
754: try {
755: MessageDigest md5 = MessageDigest.getInstance("MD5");
756: md5.update(stream.getContent());
757: String streamDigest = SourceUtil.encodeBASE64(new String(
758: md5.digest()));
759: String targetDigest = (String) this .checksums.get(target
760: .getSourceURI());
761:
762: if (streamDigest.equals(targetDigest)) {
763: return true;
764: } else {
765: this .checksums.put(target.getSourceURI(), streamDigest);
766: return false;
767: }
768: } catch (NoSuchAlgorithmException e) {
769: // or do something:
770: return false;
771: }
772: }
773:
774: /**
775: * Print a description of the software before running
776: */
777: public static String getProlog() {
778: String lSep = SystemUtils.LINE_SEPARATOR;
779: StringBuffer msg = new StringBuffer();
780: msg
781: .append(
782: "------------------------------------------------------------------------ ")
783: .append(lSep);
784: msg.append(Constants.NAME).append(" ")
785: .append(Constants.VERSION).append(lSep);
786: msg.append("Copyright (c) ").append(Constants.YEAR).append(
787: " Apache Software Foundation. All rights reserved.")
788: .append(lSep);
789: msg
790: .append(
791: "------------------------------------------------------------------------ ")
792: .append(lSep).append(lSep);
793: return msg.toString();
794: }
795: }
|