1 18 19 package org.apache.tools.ant.taskdefs; 20 21 import java.io.BufferedReader ; 22 import java.io.BufferedWriter ; 23 import java.io.File ; 24 import java.io.FileInputStream ; 25 import java.io.FileNotFoundException ; 26 import java.io.FileOutputStream ; 27 import java.io.FileReader ; 28 import java.io.FileWriter ; 29 import java.io.IOException ; 30 import java.io.InputStreamReader ; 31 import java.io.OutputStreamWriter ; 32 import java.io.Reader ; 33 import java.io.Writer ; 34 import java.util.Enumeration ; 35 import java.util.Properties ; 36 import java.util.Vector ; 37 import org.apache.tools.ant.BuildException; 38 import org.apache.tools.ant.DirectoryScanner; 39 import org.apache.tools.ant.Project; 40 import org.apache.tools.ant.util.FileUtils; 41 import org.apache.tools.ant.util.StringUtils; 42 43 54 public class Replace extends MatchingTask { 55 56 private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); 57 58 private File src = null; 59 private NestedString token = null; 60 private NestedString value = new NestedString(); 61 62 private File propertyFile = null; 63 private File replaceFilterFile = null; 64 private Properties properties = null; 65 private Vector replacefilters = new Vector (); 66 67 private File dir = null; 68 69 private int fileCount; 70 private int replaceCount; 71 private boolean summary = false; 72 73 74 private String encoding = null; 75 76 79 public class NestedString { 80 81 private StringBuffer buf = new StringBuffer (); 82 83 88 public void addText(String val) { 89 buf.append(val); 90 } 91 92 95 public String getText() { 96 return buf.toString(); 97 } 98 } 99 100 103 public class Replacefilter { 104 private String token; 105 private String value; 106 private String replaceValue; 107 private String property; 108 109 private StringBuffer inputBuffer; 110 private StringBuffer outputBuffer = new StringBuffer (); 111 112 116 public void validate() throws BuildException { 117 if (token == null) { 119 String message = "token is a mandatory attribute " 120 + "of replacefilter."; 121 throw new BuildException(message); 122 } 123 124 if ("".equals(token)) { 125 String message = "The token attribute must not be an empty " 126 + "string."; 127 throw new BuildException(message); 128 } 129 130 if ((value != null) && (property != null)) { 132 String message = "Either value or property " 133 + "can be specified, but a replacefilter " 134 + "element cannot have both."; 135 throw new BuildException(message); 136 } 137 138 if ((property != null)) { 139 if (propertyFile == null) { 141 String message = "The replacefilter's property attribute " 142 + "can only be used with the replacetask's " 143 + "propertyFile attribute."; 144 throw new BuildException(message); 145 } 146 147 if (properties == null 149 || properties.getProperty(property) == null) { 150 String message = "property \"" + property 151 + "\" was not found in " + propertyFile.getPath(); 152 throw new BuildException(message); 153 } 154 } 155 156 replaceValue = getReplaceValue(); 157 } 158 159 163 public String getReplaceValue() { 164 if (property != null) { 165 return properties.getProperty(property); 166 } else if (value != null) { 167 return value; 168 } else if (Replace.this.value != null) { 169 return Replace.this.value.getText(); 170 } else { 171 return ""; 173 } 174 } 175 176 180 public void setToken(String token) { 181 this.token = token; 182 } 183 184 188 public String getToken() { 189 return token; 190 } 191 192 197 public void setValue(String value) { 198 this.value = value; 199 } 200 201 205 public String getValue() { 206 return value; 207 } 208 209 214 public void setProperty(String property) { 215 this.property = property; 216 } 217 218 223 public String getProperty() { 224 return property; 225 } 226 227 232 StringBuffer getOutputBuffer() { 233 return outputBuffer; 234 } 235 236 244 void setInputBuffer(StringBuffer input) { 245 inputBuffer = input; 246 } 247 248 256 boolean process() { 257 if (inputBuffer.length() > token.length()) { 258 int pos = replace(); 259 pos = Math.max((inputBuffer.length() - token.length()), pos); 260 outputBuffer.append(inputBuffer.substring(0, pos)); 261 inputBuffer.delete(0, pos); 262 return true; 263 } 264 return false; 265 } 266 267 272 void flush() { 273 replace(); 274 outputBuffer.append(inputBuffer.toString()); 276 inputBuffer.delete(0, inputBuffer.length()); 277 } 278 279 284 private int replace() { 285 int found = inputBuffer.toString().indexOf(token); 286 int pos = -1; 287 while (found >= 0) { 288 inputBuffer.replace(found, found + token.length(), 289 replaceValue); 290 pos = found + replaceValue.length(); 291 found = inputBuffer.toString().indexOf(token, pos); 292 ++replaceCount; 293 } 294 return pos; 295 } 296 } 297 298 303 private class FileInput { 304 private StringBuffer outputBuffer; 305 private Reader reader; 306 private char[] buffer; 307 private static final int BUFF_SIZE = 4096; 308 309 314 FileInput(File source) throws IOException { 315 outputBuffer = new StringBuffer (); 316 buffer = new char[BUFF_SIZE]; 317 if (encoding == null) { 318 reader = new BufferedReader (new FileReader (source)); 319 } else { 320 reader = new BufferedReader (new InputStreamReader ( 321 new FileInputStream (source), encoding)); 322 } 323 } 324 325 330 StringBuffer getOutputBuffer() { 331 return outputBuffer; 332 } 333 334 339 boolean readChunk() throws IOException { 340 int bufferLength = 0; 341 bufferLength = reader.read(buffer); 342 if (bufferLength < 0) { 343 return false; 344 } 345 outputBuffer.append(new String (buffer, 0, bufferLength)); 346 return true; 347 } 348 349 353 void close() throws IOException { 354 reader.close(); 355 } 356 357 360 void closeQuietly() { 361 FileUtils.close(reader); 362 } 363 364 } 365 366 371 private class FileOutput { 372 private StringBuffer inputBuffer; 373 private Writer writer; 374 375 380 FileOutput(File out) throws IOException { 381 if (encoding == null) { 382 writer = new BufferedWriter (new FileWriter (out)); 383 } else { 384 writer = new BufferedWriter (new OutputStreamWriter 385 (new FileOutputStream (out), encoding)); 386 } 387 } 388 389 397 void setInputBuffer(StringBuffer input) { 398 inputBuffer = input; 399 } 400 401 408 boolean process() throws IOException { 409 writer.write(inputBuffer.toString()); 410 inputBuffer.delete(0, inputBuffer.length()); 411 return false; 412 } 413 414 418 void flush() throws IOException { 419 process(); 420 writer.flush(); 421 } 422 423 427 void close() throws IOException { 428 writer.close(); 429 } 430 431 434 void closeQuietly() { 435 FileUtils.close(writer); 436 } 437 } 438 439 443 public void execute() throws BuildException { 444 445 Vector savedFilters = (Vector ) replacefilters.clone(); 446 Properties savedProperties = 447 properties == null ? null : (Properties ) properties.clone(); 448 449 if (token != null) { 450 StringBuffer val = new StringBuffer (value.getText()); 454 stringReplace(val, "\r\n", "\n"); 455 stringReplace(val, "\n", StringUtils.LINE_SEP); 456 StringBuffer tok = new StringBuffer (token.getText()); 457 stringReplace(tok, "\r\n", "\n"); 458 stringReplace(tok, "\n", StringUtils.LINE_SEP); 459 Replacefilter firstFilter = createPrimaryfilter(); 460 firstFilter.setToken(tok.toString()); 461 firstFilter.setValue(val.toString()); 462 } 463 464 try { 465 if (replaceFilterFile != null) { 466 Properties props = getProperties(replaceFilterFile); 467 Enumeration e = props.keys(); 468 while (e.hasMoreElements()) { 469 String tok = e.nextElement().toString(); 470 Replacefilter replaceFilter = createReplacefilter(); 471 replaceFilter.setToken(tok); 472 replaceFilter.setValue(props.getProperty(tok)); 473 } 474 } 475 476 validateAttributes(); 477 478 if (propertyFile != null) { 479 properties = getProperties(propertyFile); 480 } 481 482 validateReplacefilters(); 483 fileCount = 0; 484 replaceCount = 0; 485 486 if (src != null) { 487 processFile(src); 488 } 489 490 if (dir != null) { 491 DirectoryScanner ds = super.getDirectoryScanner(dir); 492 String [] srcs = ds.getIncludedFiles(); 493 494 for (int i = 0; i < srcs.length; i++) { 495 File file = new File (dir, srcs[i]); 496 processFile(file); 497 } 498 } 499 500 if (summary) { 501 log("Replaced " + replaceCount + " occurrences in " 502 + fileCount + " files.", Project.MSG_INFO); 503 } 504 } finally { 505 replacefilters = savedFilters; 506 properties = savedProperties; 507 } 509 } 510 511 517 public void validateAttributes() throws BuildException { 518 if (src == null && dir == null) { 519 String message = "Either the file or the dir attribute " 520 + "must be specified"; 521 throw new BuildException(message, getLocation()); 522 } 523 if (propertyFile != null && !propertyFile.exists()) { 524 String message = "Property file " + propertyFile.getPath() 525 + " does not exist."; 526 throw new BuildException(message, getLocation()); 527 } 528 if (token == null && replacefilters.size() == 0) { 529 String message = "Either token or a nested replacefilter " 530 + "must be specified"; 531 throw new BuildException(message, getLocation()); 532 } 533 if (token != null && "".equals(token.getText())) { 534 String message = "The token attribute must not be an empty string."; 535 throw new BuildException(message, getLocation()); 536 } 537 } 538 539 545 public void validateReplacefilters() 546 throws BuildException { 547 for (int i = 0; i < replacefilters.size(); i++) { 548 Replacefilter element = 549 (Replacefilter) replacefilters.elementAt(i); 550 element.validate(); 551 } 552 } 553 554 560 public Properties getProperties(File propertyFile) throws BuildException { 561 Properties props = new Properties (); 562 563 FileInputStream in = null; 564 try { 565 in = new FileInputStream (propertyFile); 566 props.load(in); 567 } catch (FileNotFoundException e) { 568 String message = "Property file (" + propertyFile.getPath() 569 + ") not found."; 570 throw new BuildException(message); 571 } catch (IOException e) { 572 String message = "Property file (" + propertyFile.getPath() 573 + ") cannot be loaded."; 574 throw new BuildException(message); 575 } finally { 576 FileUtils.close(in); 577 } 578 579 return props; 580 } 581 582 590 private void processFile(File src) throws BuildException { 591 if (!src.exists()) { 592 throw new BuildException("Replace: source file " + src.getPath() 593 + " doesn't exist", getLocation()); 594 } 595 596 File temp = null; 597 FileInput in = null; 598 FileOutput out = null; 599 try { 600 in = new FileInput(src); 601 602 temp = FILE_UTILS.createTempFile("rep", ".tmp", 603 src.getParentFile()); 604 out = new FileOutput(temp); 605 606 int repCountStart = replaceCount; 607 608 logFilterChain(src.getPath()); 609 610 out.setInputBuffer(buildFilterChain(in.getOutputBuffer())); 611 612 while (in.readChunk()) { 613 if (processFilterChain()) { 614 out.process(); 615 } 616 } 617 618 flushFilterChain(); 619 620 out.flush(); 621 in.close(); 622 in = null; 623 out.close(); 624 out = null; 625 626 boolean changes = (replaceCount != repCountStart); 627 if (changes) { 628 FILE_UTILS.rename(temp, src); 629 temp = null; 630 } 631 } catch (IOException ioe) { 632 throw new BuildException("IOException in " + src + " - " 633 + ioe.getClass().getName() + ":" 634 + ioe.getMessage(), ioe, getLocation()); 635 } finally { 636 if (null != in) { 637 in.closeQuietly(); 638 } 639 if (null != out) { 640 out.closeQuietly(); 641 } 642 if (temp != null) { 643 if (!temp.delete()) { 644 temp.deleteOnExit(); 645 } 646 } 647 } 648 } 649 650 653 private void flushFilterChain() { 654 for (int i = 0; i < replacefilters.size(); i++) { 655 Replacefilter filter = (Replacefilter) replacefilters.elementAt(i); 656 filter.flush(); 657 } 658 } 659 660 664 private boolean processFilterChain() { 665 for (int i = 0; i < replacefilters.size(); i++) { 666 Replacefilter filter = (Replacefilter) replacefilters.elementAt(i); 667 if (!filter.process()) { 668 return false; 669 } 670 } 671 return true; 672 } 673 674 680 private StringBuffer buildFilterChain(StringBuffer inputBuffer) { 681 StringBuffer buf = inputBuffer; 682 for (int i = 0; i < replacefilters.size(); i++) { 683 Replacefilter filter = (Replacefilter) replacefilters.elementAt(i); 684 filter.setInputBuffer(buf); 685 buf = filter.getOutputBuffer(); 686 } 687 return buf; 688 } 689 690 694 private void logFilterChain(String filename) { 695 for (int i = 0; i < replacefilters.size(); i++) { 696 Replacefilter filter = (Replacefilter) replacefilters.elementAt(i); 697 log("Replacing in " + filename + ": " + filter.getToken() 698 + " --> " + filter.getReplaceValue(), Project.MSG_VERBOSE); 699 } 700 } 701 705 public void setFile(File file) { 706 this.src = file; 707 } 708 709 717 public void setSummary(boolean summary) { 718 this.summary = summary; 719 } 720 721 722 728 public void setReplaceFilterFile(File replaceFilterFile) { 729 this.replaceFilterFile = replaceFilterFile; 730 } 731 732 737 public void setDir(File dir) { 738 this.dir = dir; 739 } 740 741 747 public void setToken(String token) { 748 createReplaceToken().addText(token); 749 } 750 751 756 public void setValue(String value) { 757 createReplaceValue().addText(value); 758 } 759 760 766 public void setEncoding(String encoding) { 767 this.encoding = encoding; 768 } 769 770 774 public NestedString createReplaceToken() { 775 if (token == null) { 776 token = new NestedString(); 777 } 778 return token; 779 } 780 781 785 public NestedString createReplaceValue() { 786 return value; 787 } 788 789 795 public void setPropertyFile(File propertyFile) { 796 this.propertyFile = propertyFile; 797 } 798 799 803 public Replacefilter createReplacefilter() { 804 Replacefilter filter = new Replacefilter(); 805 replacefilters.addElement(filter); 806 return filter; 807 } 808 809 814 private Replacefilter createPrimaryfilter() { 815 Replacefilter filter = new Replacefilter(); 816 replacefilters.insertElementAt(filter, 0); 817 return filter; 818 } 819 820 823 private void stringReplace(StringBuffer str, String str1, String str2) { 824 int found = str.toString().indexOf(str1); 825 while (found >= 0) { 826 str.replace(found, found + str1.length(), str2); 827 found = str.toString().indexOf(str1, found + str2.length()); 828 } 829 } 830 831 } 832 | Popular Tags |