1 /* 2 * Copyright (C) Christian Schulte, 2005-206 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * o Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * o Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 19 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $JOMC: LineEditor.java 3875 2011-10-19 09:17:25Z schulte2005 $ 29 * 30 */ 31 package org.jomc.util; 32 33 import java.io.BufferedReader; 34 import java.io.IOException; 35 import java.io.StringReader; 36 37 /** 38 * Interface to line based editing. 39 * 40 * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a> 41 * @version $JOMC: LineEditor.java 3875 2011-10-19 09:17:25Z schulte2005 $ 42 * 43 * @see #edit(java.lang.String) 44 */ 45 public class LineEditor 46 { 47 48 /** Editor to chain. */ 49 private LineEditor editor; 50 51 /** Line separator. */ 52 private String lineSeparator; 53 54 /** 55 * Current line number. 56 * @since 1.2 57 */ 58 private long lineNumber; 59 60 /** Creates a new {@code LineEditor} instance. */ 61 public LineEditor() 62 { 63 this( null, null ); 64 } 65 66 /** 67 * Creates a new {@code LineEditor} instance taking a string to use for separating lines. 68 * 69 * @param lineSeparator String to use for separating lines. 70 */ 71 public LineEditor( final String lineSeparator ) 72 { 73 this( null, lineSeparator ); 74 } 75 76 /** 77 * Creates a new {@code LineEditor} instance taking an editor to chain. 78 * 79 * @param editor The editor to chain. 80 */ 81 public LineEditor( final LineEditor editor ) 82 { 83 this( editor, null ); 84 } 85 86 /** 87 * Creates a new {@code LineEditor} instance taking an editor to chain and a string to use for separating lines. 88 * 89 * @param editor The editor to chain. 90 * @param lineSeparator String to use for separating lines. 91 */ 92 public LineEditor( final LineEditor editor, final String lineSeparator ) 93 { 94 super(); 95 this.editor = editor; 96 this.lineSeparator = lineSeparator; 97 this.lineNumber = 0L; 98 } 99 100 /** 101 * Gets the line separator of the editor. 102 * 103 * @return The line separator of the editor. 104 */ 105 public final String getLineSeparator() 106 { 107 if ( this.lineSeparator == null ) 108 { 109 this.lineSeparator = System.getProperty( "line.separator", "\n" ); 110 } 111 112 return this.lineSeparator; 113 } 114 115 /** 116 * Gets the current line number. 117 * 118 * @return The current line number. 119 * 120 * @since 1.2 121 */ 122 public final long getLineNumber() 123 { 124 return this.lineNumber; 125 } 126 127 /** 128 * Edits text. 129 * <p>This method splits the given string into lines and passes every line to method {@code editLine} in order of 130 * occurrence. On end of input, method {@code editLine} is called with a {@code null} argument.</p> 131 * 132 * @param text The text to edit or {@code null}. 133 * 134 * @return The edited text or {@code null}. 135 * 136 * @throws IOException if editing fails. 137 */ 138 public final String edit( final String text ) throws IOException 139 { 140 String edited = text; 141 this.lineNumber = 0L; 142 BufferedReader reader = null; 143 boolean suppressExceptionOnClose = true; 144 145 try 146 { 147 if ( edited != null ) 148 { 149 final StringBuilder buf = new StringBuilder( edited.length() + 16 ); 150 boolean appended = false; 151 152 if ( edited.length() > 0 ) 153 { 154 reader = new BufferedReader( new StringReader( edited ) ); 155 156 String line = null; 157 while ( ( line = reader.readLine() ) != null ) 158 { 159 this.lineNumber++; 160 final String replacement = this.editLine( line ); 161 if ( replacement != null ) 162 { 163 buf.append( replacement ).append( this.getLineSeparator() ); 164 appended = true; 165 } 166 } 167 } 168 else 169 { 170 this.lineNumber++; 171 final String replacement = this.editLine( edited ); 172 if ( replacement != null ) 173 { 174 buf.append( replacement ).append( this.getLineSeparator() ); 175 appended = true; 176 } 177 } 178 179 final String replacement = this.editLine( null ); 180 if ( replacement != null ) 181 { 182 buf.append( replacement ); 183 appended = true; 184 } 185 186 edited = appended ? buf.toString() : null; 187 } 188 189 if ( this.editor != null ) 190 { 191 edited = this.editor.edit( edited ); 192 } 193 194 suppressExceptionOnClose = false; 195 return edited; 196 } 197 finally 198 { 199 try 200 { 201 if ( reader != null ) 202 { 203 reader.close(); 204 } 205 } 206 catch ( final IOException e ) 207 { 208 if ( !suppressExceptionOnClose ) 209 { 210 throw e; 211 } 212 } 213 } 214 } 215 216 /** 217 * Edits a line. 218 * 219 * @param line The line to edit or {@code null}, indicating the end of input. 220 * 221 * @return The string to replace {@code line} with or {@code null}, to replace {@code line} with nothing. 222 * 223 * @throws IOException if editing fails. 224 */ 225 protected String editLine( final String line ) throws IOException 226 { 227 return line; 228 } 229 230 }