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 < to &lt; and > to &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 += "<"; 361 } 362 else if ( ch == '>' ) 363 { 364 retVal += ">"; 365 } 366 else if ( ch == '&' ) 367 { 368 retVal += "&"; 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