View Javadoc
1   package org.apache.maven.shared.scriptinterpreter;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.OutputStream;
26  import java.io.PrintStream;
27  
28  /**
29   * <p>FileLogger class.</p>
30   *
31   */
32  public class FileLogger implements ExecutionLogger, AutoCloseable
33  {
34  
35      /**
36       * The path to the log file.
37       */
38      private File file;
39  
40      /**
41       * The underlying file stream this logger writes to.
42       */
43      private PrintStream stream;
44  
45      /**
46       * Creates a new logger that writes to the specified file.
47       *
48       * @param outputFile The path to the output file, if null all message will be discarded.
49       * @throws java.io.IOException If the output file could not be created.
50       */
51      public FileLogger( File outputFile ) throws IOException
52      {
53          this( outputFile, null );
54      }
55  
56      /**
57       * Creates a new logger that writes to the specified file and optionally mirrors messages.
58       *
59       * @param outputFile The path to the output file, if null all message will be discarded.
60       * @param mirrorHandler The class which handle mirrored message, can be <code>null</code>.
61       * @throws java.io.IOException If the output file could not be created.
62       */
63      public FileLogger( File outputFile, FileLoggerMirrorHandler mirrorHandler ) throws IOException
64      {
65          this.file = outputFile;
66  
67          OutputStream outputStream;
68  
69          if ( outputFile != null )
70          {
71              outputFile.getParentFile().mkdirs();
72              outputStream = new FileOutputStream( outputFile );
73          }
74          else
75          {
76              outputStream = new NullOutputStream();
77          }
78  
79          if ( mirrorHandler != null )
80          {
81              stream = new PrintStream( new MirrorStreamWrapper( outputStream, mirrorHandler ) );
82          }
83          else
84          {
85              stream = new PrintStream( outputStream );
86          }
87      }
88  
89      /**
90       * Gets the path to the output file.
91       *
92       * @return The path to the output file, never <code>null</code>.
93       */
94      public File getOutputFile()
95      {
96          return file;
97      }
98  
99      /**
100      * Gets the underlying stream used to write message to the log file.
101      *
102      * @return The underlying stream used to write message to the log file, never <code>null</code>.
103      */
104     @Override
105     public PrintStream getPrintStream()
106     {
107         return stream;
108     }
109 
110     /**
111      * Writes the specified line to the log file
112      * and invoke {@link FileLoggerMirrorHandler#consumeOutput(String)} if is given.
113      *
114      * @param line The message to log.
115      */
116     @Override
117     public void consumeLine( String line )
118     {
119         stream.println( line );
120         stream.flush();
121     }
122 
123     /**
124      * Closes the underlying file stream.
125      */
126     public void close()
127     {
128         if ( stream != null )
129         {
130             stream.flush();
131             stream.close();
132             stream = null;
133         }
134    }
135 
136     private static class MirrorStreamWrapper extends OutputStream
137     {
138         private final OutputStream out;
139         private final FileLoggerMirrorHandler mirrorHandler;
140 
141         private StringBuilder lineBuffer;
142 
143         MirrorStreamWrapper( OutputStream outputStream, FileLoggerMirrorHandler mirrorHandler )
144         {
145             this.out = outputStream;
146             this.mirrorHandler = mirrorHandler;
147             this.lineBuffer = new StringBuilder();
148         }
149 
150         @Override
151         public void write( int b ) throws IOException
152         {
153             out.write( b );
154             lineBuffer.append( (char) ( b ) );
155         }
156 
157         @Override
158         public void write( byte[] b, int off, int len ) throws IOException
159         {
160             out.write( b, off, len );
161             lineBuffer.append( new String( b, off, len ) );
162         }
163 
164         @Override
165         public void flush() throws IOException
166         {
167             out.flush();
168 
169             int len = lineBuffer.length();
170             if ( len == 0 )
171             {
172                 // nothing to log
173                 return;
174             }
175 
176             // remove line end for log
177             while ( len > 0 && ( lineBuffer.charAt( len - 1 ) == '\n' || lineBuffer.charAt( len - 1 ) == '\r' ) )
178             {
179                 len--;
180             }
181             lineBuffer.setLength( len );
182 
183             mirrorHandler.consumeOutput( lineBuffer.toString() );
184 
185             // clear buffer
186             lineBuffer = new StringBuilder();
187         }
188     }
189 
190     private static class NullOutputStream extends OutputStream
191     {
192         @Override
193         public void write( int b )
194         {
195             // do nothing
196         }
197 
198         @Override
199         public void write( byte[] b, int off, int len )
200         {
201             // do nothing
202         }
203     }
204 }