001/*
002 *  AstroVersion.java
003 *  $URL: svn://svn/open/trunk/www/astroVersion/WEB-INF/src/ca/bc/webarts/widgets/AstroVersion.java $
004 *  $Revision: 576 $
005 *  $LastChangedDate: 2012-11-18 16:30:11 -0800 (Sun, 18 Nov 2012) $
006 *  $LastChangedBy: tgutwin $
007 *  Copyright (c) 2005-2012 Tom B. Gutwin P.Eng.
008 *  http://www.webarts.bc.ca
009 *
010 *  This program is free software; you can redistribute it and/or
011 *  modify it under the terms of the GNU General Public License
012 *  as published by the Free Software Foundation; either version 2
013 *  of the License, or any later version.
014 *
015 *  This program is distributed in the hope that it will be useful,
016 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
017 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
018 *  GNU General Public License for more details.
019 *
020 *  You should have received a copy of the GNU General Public License
021 *  along with this program; if not, write to the Free Software
022 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
023 */
024package ca.bc.webarts.widgets;
025
026import java.io.ByteArrayInputStream;
027import java.io.ByteArrayOutputStream;
028import java.io.File;
029import java.io.FileOutputStream;
030import java.io.OutputStream;
031import java.io.PrintStream;
032import java.io.StringWriter;
033import java.util.ArrayList;
034import java.util.Collection;
035import java.util.Comparator;
036import java.util.Iterator;
037import java.util.HashMap;
038import java.util.Map;
039import java.util.TreeMap;
040import org.tmatesoft.svn.core.io.ISVNLogEntryHandler;
041import org.tmatesoft.svn.core.ISVNWorkspace;
042import org.tmatesoft.svn.core.io.SVNDirEntry;
043import org.tmatesoft.svn.core.io.SVNException;
044import org.tmatesoft.svn.core.io.SVNLogEntry;
045import org.tmatesoft.svn.core.io.SVNNodeKind;
046import org.tmatesoft.svn.core.io.SVNURL;
047import org.tmatesoft.svn.core.SVNWorkspaceManager;
048import org.tmatesoft.svn.core.diff.*;
049import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
050import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
051import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
052import org.tmatesoft.svn.core.io.*;
053import org.tmatesoft.svn.core.io.SVNFileRevision;
054import org.tmatesoft.svn.core.io.SVNRepository;
055import org.tmatesoft.svn.core.io.SVNRepositoryLocation;
056import org.tmatesoft.svn.core.io.diff.SVNDiffWindow;
057import org.tmatesoft.svn.util.PathUtil;
058import org.tmatesoft.svn.util.SVNUtil;
059import org.tigris.subversion.javahl.ClientException;
060import org.tigris.subversion.javahl.Revision;
061import org.tigris.subversion.javahl.SVNClient;
062
063import bmsi.util.Diff;
064import bmsi.util.DiffPrint;
065
066
067
068/**
069 *  This is a helper bean for the astroVersion webapp. The web app is a web
070 *  viewer for Subversion repositories and is written entirely in
071 *  Java/JSP/Servlets. <br>
072 *  This class acts as a helper to the jsps for the web app and performs SVN
073 *  lookup functionality to remove the grunt-work from the JSP pages. It uses
074 *  the JavaSVN library for doing its SVN access. <br>
075 *  <br>
076 *  Copyright (c) 2005-2012 Tom B. Gutwin P.Eng.<br>
077 *  <img src="http://www.webarts.bc.ca/webArts/images/tbgEmail.png"
078 *       alt="tbg email address"><br>
079 *  <a href="http://www.webarts.bc.ca">http://www.webarts.bc.ca</a> <br>
080 *  <a href="http://svn.webarts.bc.ca">http://svn.webarts.bc.ca</a> <br>
081 *
082 *
083 * @author    tgutwin
084 */
085public class AstroVersion
086{
087  /**  Class holder for the currently used repo location object. */
088  SVNRepositoryLocation location_ = null;
089  /**  Class holder for the currently used repo location object. */
090  SVNRepository repository_ = null;
091  ISVNWorkspace workspace_ = null;
092  SVNURL svnURL_ = null;
093
094  /**  Class flag keeping track if the repo has been setup for use. */
095  boolean repoIsInit_ = false;
096  /**  Class holder for file revision log information that needs to be shared
097       with internal private classes. */
098  TreeMap revLogHashTree_ = new TreeMap();
099  /**  Class holder for file revision information that needs to be shared
100       with internal private classes. */
101  //TreeMap fileRevHashTree_ = new TreeMap();
102
103
104  /**
105   *  Setup the SVN Repository objects as required by the JavaSVN Library.
106   *
107   * @param  repository        The String representation of the URL for the
108   *                           repository to access.
109   * @exception  SVNException  Thrown if issues with the spec'd repo.
110   */
111  public void initRepo( String repository )
112    throws SVNException
113  {
114    if ( !repoIsInit_ )
115    {
116      // for DAV (over http and https)
117      DAVRepositoryFactory.setup();
118      // for SVN (over svn and svn+ssh)
119      SVNRepositoryFactoryImpl.setup();
120      // Working copy storage (default is file system).
121      FSRepositoryFactory.setup();
122      svnURL_ = SVNURL.parseURIDecoded(repository);
123
124      repoIsInit_ = true;
125    }
126    repository_ = SVNRepositoryFactory.create( svnURL_ );
127
128  }
129
130
131  /**
132   *  Retrieves the file from the repo and returns it as a String. It can be
133   *  used to return a text based file for viewing. The parameters describe the
134   *  file, revision, and location in the repo to retrieve.
135   *
136   * @param  repo      The repo to use for the retrieval
137   * @param  filePath  The repo sub path (including the filename) to get the
138   *                   file from.
139   * @param  rev       The revision number to retrieve.
140   * @return           The fileContents as a String
141   */
142  public String getFileContents( String repo, String filePath, String rev )
143  {
144    String retVal = null;
145    try
146    {
147      initRepo( repo );
148      long revision = ISVNWorkspace.HEAD;
149      try
150      {
151        revision = Long.parseLong( rev.trim() );
152      }
153      catch ( java.lang.NumberFormatException numEx )
154      {
155        revision = ISVNWorkspace.HEAD;
156      }
157      retVal = cat( filePath, revision );
158    }
159    catch ( SVNException e )
160    {
161      e.printStackTrace();
162    }
163    return retVal;
164  }
165
166
167  /**
168   *  Retrieves the file from the repo and returns it as bytes. It can be
169   *  used to return the raw bytes of a file. The parameters describe the
170   *  file, revision, and location in the repo to retrieve.
171   *
172   * @param  repo      The repo to use for the retrieval
173   * @param  filePath  The repo sub path (including the filename) to get the
174   *                   file from.
175   * @param  rev       The revision number to retrieve.
176   * @return           The fileContents as a an array of bytes
177   */
178  public byte[] getFileBytes( String repo, String filePath, String rev )
179  {
180    byte[] retVal = null;
181    try
182    {
183      initRepo( repo );
184      long revision = ISVNWorkspace.HEAD;
185      try
186      {
187        revision = Long.parseLong( rev.trim() );
188      }
189      catch ( java.lang.NumberFormatException numEx )
190      {
191        revision = ISVNWorkspace.HEAD;
192      }
193      retVal = catBytes( filePath, revision );
194    }
195    catch ( SVNException e )
196    {
197      e.printStackTrace();
198    }
199    return retVal;
200  }
201
202
203  /**
204   *  Retrieves the file from the repo and returns it as bytes. It can be
205   *  used to return the raw bytes of a file. The parameters describe the
206   *  file, revision, and location in the repo to retrieve.
207   *
208   * @param  repo      The repo to use for the retrieval
209   * @param  filePath  The repo sub path (including the filename) to get the
210   *                   file from.
211   * @param  rev       The revision number to retrieve.
212   * @return           The fileContents as a an array of bytes
213   * @throws           If one of the rev numbers is invalid (ie negative)
214   */
215  public byte[] getFileDiffBytes( String repo, String filePath, String rev , String rev2 )
216    throws IllegalArgumentException, ClientException
217  {
218    byte[] retVal = null;
219    String tmp = getFileDiff(repo, filePath, rev , rev2);
220    if ( tmp!=null)
221      retVal = tmp.getBytes();
222    return retVal;
223  }
224
225
226  /**
227   *  Retrieves the file from the repo and returns it as bytes. It can be
228   *  used to return the raw bytes of a file. The parameters describe the
229   *  file, revision, and location in the repo to retrieve.
230   *
231   * @param  repo      The repo to use for the retrieval
232   * @param  filePath  The repo sub path (including the filename) to get the
233   *                   file from.
234   * @param  rev       The revision number to retrieve.
235   * @return           The fileContents as a an array of bytes
236   * @throws           If one of the rev numbers is invalid (ie negative)
237   */
238  public String getFileDiff( String repo, String filePath,
239                                String rev , String rev2 )
240  {
241    String retVal = null;
242    String rev1Str = null;
243    String rev2Str = null;
244    /*
245       style can be:
246         'n' for normal style
247         'e' for ed editor style
248         'c' for  context style
249         'u' for unified style
250    */
251    char style = 'n';
252    boolean reverse = style == 'e';
253    StringWriter strOutWriter = new StringWriter();
254    rev1Str = getFileContents(repo, filePath, rev);
255    rev2Str = getFileContents(repo, filePath, rev2);
256    String [] rev1Lines = rev1Str.split("[\r\n]");
257    String [] rev2Lines = rev2Str.split("[\r\n]");
258
259    // on with the diff
260    Diff diff = new Diff(rev1Lines,rev2Lines);
261    Diff.change script = diff.diff_2( reverse );
262    if ( script == null )
263    {
264      strOutWriter.write("No differences\n");
265      //System.err.println( "No differences" );
266    }
267    else
268    {
269      DiffPrint.Base p;
270      switch ( style )
271      {
272        case 'e':
273          p = new DiffPrint.EdPrint( rev1Lines,rev2Lines);
274          break;
275        case 'c':
276          p = new DiffPrint.ContextPrint( rev1Lines,rev2Lines );
277          break;
278        case 'u':
279          p = new DiffPrint.UnifiedPrint( rev1Lines,rev2Lines );
280          break;
281        default:
282          p = new DiffPrint.NormalPrint( rev1Lines,rev2Lines );
283      }
284      p.setOutput(strOutWriter);
285      //p.print_header( filePath+" rev:"+rev, filePath+" rev:"+rev2 );
286      p.print_script( script );
287    }
288
289    return strOutWriter.toString();
290  }
291
292
293    /**
294   *  Retrieves the file from the repo and returns it as bytes. It can be
295   *  used to return the raw bytes of a file. The parameters describe the
296   *  file, revision, and location in the repo to retrieve.
297   *
298   * @param  repo      The repo to use for the retrieval
299   * @param  filePath  The repo sub path (including the filename) to get the
300   *                   file from.
301   * @param  rev       The revision number to retrieve.
302   * @return           The fileContents as a an array of bytes
303   * @throws           If one of the rev numbers is invalid (ie negative)
304   */
305  public String getSvnFileDiff( String repo, String filePath, String rev , String rev2 )
306throws IllegalArgumentException, ClientException
307  {
308    String retVal = null;
309    try
310    {
311      initRepo( repo );
312      long revision = ISVNWorkspace.HEAD;
313      long revision2 = ISVNWorkspace.HEAD;
314      try
315      {
316        revision = Long.parseLong( rev.trim() );
317        revision2 = Long.parseLong( rev2.trim() );
318        SVNClient svnClient = new SVNClient();
319        StringWriter strOutWriter = new StringWriter();
320        Revision.Number revNumber = new Revision.Number(revision);
321        Revision.Number revNumber2 = new Revision.Number(revision2);
322        System.out.println("Calling svnClient.diff");
323        //diff(java.lang.String,org.tigris.subversion.javahl.Revision,
324        //     java.lang.String,org.tigris.subversion.javahl.Revision,java.lang.String,boolean)
325        //svnClient.diff("/tmp/svn",filePath,revNumber,revNumber2,strOutWriter);
326        retVal = svnClient.toString();
327      }
328      catch ( java.lang.NumberFormatException numEx )
329      {
330        revision = ISVNWorkspace.HEAD;
331        revision2 = ISVNWorkspace.HEAD;
332      }
333      //retVal = catBytes( filePath, revision );
334    }
335    catch ( SVNException e )
336    {
337      e.printStackTrace();
338    }
339    return retVal;
340  }
341
342
343  /**
344   *  Provides basic URL encoding of a String. It simply does some char
345   *  replacements... changes &lt; to &amp;lt;  and &gt; to &amp;gt; as well as
346   *  others.
347   *
348   * @param  bytes  A String to do the conversion.
349   * @return        The URL encoded string.
350   */
351  public String encodeString( String bytes )
352  {
353    String retVal = "";
354    for ( int i = 0; i < bytes.length(); i++ )
355    {
356      char ch = bytes.charAt( i );
357
358      if ( ch == '<' )
359      {
360        retVal += "&lt;";
361      }
362      else if ( ch == '>' )
363      {
364        retVal += "&gt;";
365      }
366      else if ( ch == '&' )
367      {
368        retVal += "&amp;";
369      }
370      else
371      {
372        retVal += ch;
373      }
374    }
375    return retVal;
376  }
377
378
379  /**
380   *  Gets the fileRevision log for a file revision from the SVNRevisionProperty log.
381   *
382   * @param  rev       the rev to get the log entry for
383   * @return           The fileRevisionEntries value
384   */
385  public String getRevisionPropertyValue( SVNFileRevision rev, String propertyName)
386      throws SVNException
387  {
388    String retVal = "";
389
390    if (rev != null)
391    {
392
393      Map properties = rev.getRevisionProperties().asMap();
394      if (false)
395      {
396        Object [] keys = properties.keySet().toArray();
397        for (int i = 0; i < properties.size(); i++)
398        {
399          //System.out.println(""+rev.getRevision()+" RevProp "+keys[i]+"="+properties.get(keys[i]));
400          if ((keys[i].toString()).trim().equals(propertyName))
401          {
402            retVal = properties.get(keys[i]).toString();
403            System.out.println("!!!!");
404          }
405        }
406      }
407      if (properties.containsKey(propertyName))
408      {
409        //System.out.println(""+rev.getRevision()+" RevProp "+propertyName+"="+properties.get(propertyName));
410        retVal = properties.get(propertyName).toString();
411      }
412    }
413    return retVal;
414  }
415
416
417  /**
418   *  Convienience method to get the fileRevision log for a file revision from the
419   *  SVNRevisionProperties. It simply calls getRevisionPropertyValue with the
420   *  propertyName 'log'.
421   *
422   * @param  rev       the rev to get the log entry for
423   * @return           The fileRevisionEntries value
424   */
425  public String getFileRevisionLog( SVNFileRevision rev )
426  {
427    String retVal = "";
428    try
429    {
430      retVal = getRevisionPropertyValue(rev, "svn:"+"log");
431    }
432    catch (SVNException svnEx)
433    {
434
435    }
436    return retVal;
437  }
438
439
440  /**
441   *  Convienience method to get the fileRevision date for a file revision from the
442   *  SVNRevisionProperties. It simply calls getRevisionPropertyValue with the
443   *  propertyName 'date'.
444   *
445   * @param  rev       the rev to get the log entry for
446   * @return           The fileRevisionEntries value
447   */
448  public String getFileRevisionDate( SVNFileRevision rev )
449  {
450    String retVal = "";
451    try
452    {
453      retVal = getRevisionPropertyValue(rev, "svn:"+"date");
454    }
455    catch (SVNException svnEx)
456    {
457
458    }
459    return retVal;
460  }
461
462
463  /**
464   *  Convienience method to get the fileRevision author for a file revision from the
465   *  SVNRevisionProperties. It simply calls getRevisionPropertyValue with the
466   *  propertyName 'author'.
467   *
468   * @param  rev       the rev to get the log entry for
469   * @return           The fileRevisionEntries value
470   */
471  public String getFileRevisionAuthor( SVNFileRevision rev )
472  {
473    String retVal = "";
474    try
475    {
476      retVal = getRevisionPropertyValue(rev, "svn:"+"author");
477    }
478    catch (SVNException svnEx)
479    {
480
481    }
482    return retVal;
483  }
484
485
486  /**
487   *  Gets the fileRevisionEntries for a file in a sorted TreeMap and puts it in the class.
488   *
489   * @param  repo      the repo to query
490   * @param  filePath  the file to get
491   * @return           The fileRevisionEntries value
492   */
493  public TreeMap getFileRevisionEntries( String repo, String filePath )
494  {
495    FileRevHandler fileRevHandler = new FileRevHandler();
496    try
497    {
498      initRepo( repo );
499      long latestRevision = repository_.getLatestRevision();
500      repository_.getFileRevisions( filePath, 0, latestRevision, fileRevHandler  );
501    }
502    catch ( SVNException e )
503    {
504      //e.printStackTrace();
505      try
506      {
507        repoIsInit_ = false;
508        initRepo( repo );
509        long latestRevision = repository_.getLatestRevision();
510        repository_.getFileRevisions( filePath, 0, latestRevision, fileRevHandler  );
511      }
512      catch ( SVNException e2 )
513      {
514        e2.printStackTrace();
515      }
516    }
517    return fileRevHandler.getFileRevHashTree();
518  }
519
520
521  /**
522   *  Gets the file Log Entries for a file in a sorted TreeMap.
523   *
524   * @param  repo      the repo to query
525   * @param  filePath  the file to get
526   * @return           The log Entries
527   */
528  public TreeMap getFileLogEntries( String repo, String filePath )
529  {
530    try
531    {
532      initRepo( repo );
533      String[] targetPaths = {filePath};
534      long latestRevision = repository_.getLatestRevision();
535      revLogHashTree_ = new TreeMap();
536      repository_.log( targetPaths, 0L, latestRevision, true, true, new RevLogHandler() );
537    }
538    catch ( SVNException e )
539    {
540      e.printStackTrace();
541    }
542    return revLogHashTree_;
543  }
544
545
546  /**
547   *  Internal helper method to do a cat on a repo file and return it as a
548   *  String.
549   *
550   * @param  path              The file path to get the cat
551   * @param  revNumber         the rev to get
552   * @return                   Description of the Return Value
553   * @exception  SVNException  Description of the Exception
554   */
555  private String cat( String path, long revNumber )
556    throws SVNException
557  {
558    return new String( catBytes( path, revNumber ) );
559  }
560
561
562  /**
563   *  Internal helper method to do a cat on a repo file and return it as raw
564   *  bytes.
565   *
566   * @param  path              Description of the Parameter
567   * @param  revNumber         Description of the Parameter
568   * @return                   Description of the Return Value
569   * @exception  SVNException  Description of the Exception
570   */
571  private byte[] catBytes( String path, long revNumber )
572    throws SVNException
573  {
574    ByteArrayOutputStream bos = new ByteArrayOutputStream();
575    repository_.getFile( path, revNumber, null, bos );
576    return bos.toByteArray();
577  }
578
579
580
581  /**
582   *  This Method Returns the right MIME type for a particular format <p>
583   *
584   *
585   *
586   * @param  format  Description of the Parameter
587   * @return         String MIMEtype
588   */
589  public static String getMimeType( String format )
590  {
591    if ( format.equalsIgnoreCase( "pdf" ) )
592    {//check the out type
593      return "application/pdf";
594    }
595    else if ( format.equalsIgnoreCase( "audio_basic" ) ||
596              format.toLowerCase().endsWith("au") )
597    {
598      return "audio/basic";
599    }
600    else if ( format.equalsIgnoreCase( "audio_wav" ) ||
601              format.toLowerCase().endsWith("wav") )
602    {
603      return "audio/wav";
604    }
605    else if ( format.equalsIgnoreCase( "audio_vorbis" ) ||
606              format.toLowerCase().endsWith("ogg") )
607    {
608      return "application/x-ogg";
609    }
610    else if ( format.equalsIgnoreCase( "image_gif" ) ||
611              format.toLowerCase().endsWith("gif") )
612    {
613      return "image/gif";
614    }
615    else if ( format.equalsIgnoreCase( "image_jpeg" ) ||
616              format.toLowerCase().endsWith("jpg") ||
617              format.toLowerCase().endsWith("jpeg") )
618    {
619      return "image/jpeg";
620    }
621    else if ( format.equalsIgnoreCase( "image_bmp" ) ||
622              format.toLowerCase().endsWith("bmp") )
623    {
624      return "image/bmp";
625    }
626    else if ( format.equalsIgnoreCase( "image_x-png" ) ||
627              format.toLowerCase().endsWith("png") )
628    {
629      return "image/x-png";
630    }
631    else if ( format.equalsIgnoreCase( "msdownload" ) ||
632              format.toLowerCase().endsWith("ms") )
633    {
634      return "application/x-msdownload";
635    }
636    else if ( format.equalsIgnoreCase( "video_avi" ) ||
637              format.toLowerCase().endsWith("avi") )
638    {
639      return "video/avi";
640    }
641    else if ( format.equalsIgnoreCase( "video_mpeg" ) ||
642              format.toLowerCase().endsWith("mpg") )
643    {
644      return "video/mpeg";
645    }
646    else if ( format.equalsIgnoreCase( "html" ) ||
647              format.toLowerCase().endsWith("html") )
648    {
649      return "text/html";
650    }
651    else if ( format.equalsIgnoreCase( "xml" ) ||
652              format.toLowerCase().endsWith("xml") )
653    {
654      return "text/xml";
655    }
656    else
657    {
658      return null;
659    }
660  }
661
662  /** Main method to do a quick debug check. This class in made to help the jsps and astroVersion servlet. **/
663  public static void main(String[] args)
664  {
665    int retVal = 0;
666    if (args.length >4)
667    {
668      String repository = args[0];
669      String dir = args[1];
670      String file = args[2];
671      String rev = args[3];
672      String rev2 = args[4];
673      AstroVersion instance = new AstroVersion();
674      try
675      {
676        String revCat = instance.getFileDiff(repository, dir+file, rev, rev2 );
677        String encodedStr = instance.encodeString(revCat);
678        System.out.println("Results:");
679        System.out.println("        "+repository+" "+dir+file+" "+rev+" "+rev2 );
680        System.out.println(encodedStr);
681      }
682      catch (Exception clEx)
683      {
684        System.out.println("Error:");
685        clEx.printStackTrace();
686      }
687    }
688    else
689      System.out.println("Wrong number of args.");
690
691  }
692
693
694  /**
695   *  A event handler class to do somehting when the log events come in during
696   *  a log command.
697   *
698   */
699  private class RevLogHandler implements ISVNLogEntryHandler
700  {
701    /**
702     *  Handles the log entry.
703     *
704     * @param  logEntry  spec'd by the interface
705     */
706    public void handleLogEntry( SVNLogEntry logEntry )
707    {
708      long revision = logEntry.getRevision();
709      String logMessage = logEntry.getMessage();
710      revLogHashTree_.put( new Long( revision ), logEntry );
711    }
712  }
713
714
715  /**
716   *  A event handler class to do somehting when the file revision events come in during
717   *  a getFileRevisions command.
718   *
719   */
720  private class FileRevHandler implements ISVNFileRevisionHandler
721  {
722    TreeMap fileRevHashTree = new TreeMap();
723
724    /**
725     *  Handles the rev, implemented for the ISVNFileRevisionHandler interface
726     *
727     * @param  logEntry  spec'd by the interface
728     */
729    public void openRevision(SVNFileRevision fileRevision)
730    {
731      long revision = fileRevision.getRevision();
732      this.fileRevHashTree.put( new Long( revision ), fileRevision );
733    }
734
735    /**
736     *  Does NOTHING, implemented for the ISVNFileRevisionHandler interface
737     *
738     * @param  token  spec'd by the interface
739     */
740    public void closeRevision(String token)
741    {
742    }
743
744
745    /**
746    *  Collects a next delta chunk, implemented for the ISVNFileRevisionHandler interface
747    *
748    * @param  path - a file path relative to the edit root directory  spec'd by the interface
749    * @param  diffWindow - a next diff window   spec'd by the interface
750    */
751    public OutputStream textDeltaChunk(String path,
752                                       SVNDiffWindow diffWindow)
753    {
754      OutputStream retVal = new ByteArrayOutputStream();
755
756      return retVal;
757    }
758
759
760    /**
761     *  Does NOTHING, implemented for the ISVNFileRevisionHandler interface
762     *
763     */
764    public void applyTextDelta(String path, String baseChecksum)
765    {
766    }
767
768
769    /**
770     *  Does NOTHING, implemented for the ISVNFileRevisionHandler interface
771     *
772     */
773    public void textDeltaEnd(java.lang.String path)
774    {
775    }
776
777
778    public TreeMap getFileRevHashTree()
779    {
780      return fileRevHashTree;
781    }
782  }
783}
784/*
785 *  AstroVersion.java
786 *  $Id: AstroVersion.java 576 2012-11-19 00:30:11Z tgutwin $
787 */
788