View Javadoc
1   /*
2    *   Copyright (C) 2005 Christian Schulte <cs@schulte.it>
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 5091 2016-04-04 15:40:17Z schulte $
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:cs@schulte.it">Christian Schulte</a>
41   * @version $JOMC: LineEditor.java 5091 2016-04-04 15:40:17Z schulte $
42   *
43   * @see #edit(java.lang.String)
44   */
45  public class LineEditor
46  {
47  
48      /**
49       * Editor to chain.
50       */
51      private LineEditor editor;
52  
53      /**
54       * Line separator.
55       */
56      private String lineSeparator;
57  
58      /**
59       * Current line number.
60       *
61       * @since 1.2
62       */
63      private long lineNumber;
64  
65      /**
66       * Creates a new {@code LineEditor} instance.
67       */
68      public LineEditor()
69      {
70          this( null, null );
71      }
72  
73      /**
74       * Creates a new {@code LineEditor} instance taking a string to use for separating lines.
75       *
76       * @param lineSeparator String to use for separating lines.
77       */
78      public LineEditor( final String lineSeparator )
79      {
80          this( null, lineSeparator );
81      }
82  
83      /**
84       * Creates a new {@code LineEditor} instance taking an editor to chain.
85       *
86       * @param editor The editor to chain.
87       */
88      public LineEditor( final LineEditor editor )
89      {
90          this( editor, null );
91      }
92  
93      /**
94       * Creates a new {@code LineEditor} instance taking an editor to chain and a string to use for separating lines.
95       *
96       * @param editor The editor to chain.
97       * @param lineSeparator String to use for separating lines.
98       */
99      public LineEditor( final LineEditor editor, final String lineSeparator )
100     {
101         super();
102         this.editor = editor;
103         this.lineSeparator = lineSeparator;
104         this.lineNumber = 0L;
105     }
106 
107     /**
108      * Gets the line separator of the editor.
109      *
110      * @return The line separator of the editor.
111      */
112     public final String getLineSeparator()
113     {
114         if ( this.lineSeparator == null )
115         {
116             this.lineSeparator = System.getProperty( "line.separator", "\n" );
117         }
118 
119         return this.lineSeparator;
120     }
121 
122     /**
123      * Gets the current line number.
124      *
125      * @return The current line number.
126      *
127      * @since 1.2
128      */
129     public final long getLineNumber()
130     {
131         return this.lineNumber;
132     }
133 
134     /**
135      * Edits text.
136      * <p>
137      * This method splits the given string into lines and passes every line to method {@code editLine} in order of
138      * occurrence. On end of input, method {@code editLine} is called with a {@code null} argument.
139      * </p>
140      *
141      * @param text The text to edit or {@code null}.
142      *
143      * @return The edited text or {@code null}.
144      *
145      * @throws IOException if editing fails.
146      */
147     public final String edit( final String text ) throws IOException
148     {
149         String edited = text;
150         this.lineNumber = 0L;
151         BufferedReader reader = null;
152         boolean suppressExceptionOnClose = true;
153 
154         try
155         {
156             if ( edited != null )
157             {
158                 final StringBuilder buf = new StringBuilder( edited.length() + 16 );
159                 boolean appended = false;
160 
161                 if ( edited.length() > 0 )
162                 {
163                     reader = new BufferedReader( new StringReader( edited ) );
164 
165                     String line = null;
166                     while ( ( line = reader.readLine() ) != null )
167                     {
168                         this.lineNumber++;
169                         final String replacement = this.editLine( line );
170                         if ( replacement != null )
171                         {
172                             buf.append( replacement ).append( this.getLineSeparator() );
173                             appended = true;
174                         }
175                     }
176                 }
177                 else
178                 {
179                     this.lineNumber++;
180                     final String replacement = this.editLine( edited );
181                     if ( replacement != null )
182                     {
183                         buf.append( replacement ).append( this.getLineSeparator() );
184                         appended = true;
185                     }
186                 }
187 
188                 final String replacement = this.editLine( null );
189                 if ( replacement != null )
190                 {
191                     buf.append( replacement );
192                     appended = true;
193                 }
194 
195                 edited = appended ? buf.toString() : null;
196             }
197 
198             if ( this.editor != null )
199             {
200                 edited = this.editor.edit( edited );
201             }
202 
203             suppressExceptionOnClose = false;
204             return edited;
205         }
206         finally
207         {
208             try
209             {
210                 if ( reader != null )
211                 {
212                     reader.close();
213                 }
214             }
215             catch ( final IOException e )
216             {
217                 if ( !suppressExceptionOnClose )
218                 {
219                     throw e;
220                 }
221             }
222         }
223     }
224 
225     /**
226      * Edits a line.
227      *
228      * @param line The line to edit or {@code null}, indicating the end of input.
229      *
230      * @return The string to replace {@code line} with or {@code null}, to replace {@code line} with nothing.
231      *
232      * @throws IOException if editing fails.
233      */
234     protected String editLine( final String line ) throws IOException
235     {
236         return line;
237     }
238 
239 }