View Javadoc
1   /*
2    * Copyright 2007, 2008 Ange Optimization ApS
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package eu.simuline.octave.util;
17  
18  import java.io.IOException;
19  import java.io.Reader;
20  import java.io.Writer;
21  
22  import eu.simuline.octave.exception.OctaveIOException;
23  import eu.simuline.octave.exception.OctaveInterruptedException;
24  
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.commons.logging.Log;
27  
28  /**
29   * A Thread that moves data from a Reader to a Writer. 
30   * 
31   * @author Kim Hansen
32   */
33  public final class ReaderWriterPipeThread extends Thread {
34  
35      private static final Log LOG = LogFactory
36  	.getLog(ReaderWriterPipeThread.class);
37  
38      @SuppressWarnings("checkstyle:magicnumber")
39      private static final char[] BUF = new char[4 * 1024];
40   
41      private final Reader reader;
42  
43      private Writer writer;
44  
45      /**
46       * Will create a thread that reads from reader and writes to write 
47       * until reader reaches EOF. 
48       * Then the thread will close. 
49       * Remember to join() this thread before closing reader or writer.
50       * 
51       * @param reader
52       * @param writer
53       *    may be null TBC: does this make sense? 
54       * @return Returns the new thread
55       */
56      public static ReaderWriterPipeThread instantiate(final Reader reader, 
57  						     final Writer writer) {
58          final ReaderWriterPipeThread readerWriterPipeThread = 
59  	    new ReaderWriterPipeThread(reader, writer);
60          readerWriterPipeThread.setName(Thread.currentThread().getName() 
61  				       + "-javaoctave-"
62  				       + ReaderWriterPipeThread.class
63  				       .getSimpleName());
64  	readerWriterPipeThread
65  	    .setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
66  		    public void uncaughtException(Thread th, Throwable ex) {
67  			System.out.println("Uncaught : " + ex + 
68  					   " of thread " + th.getName());
69  		    }
70  		});
71          readerWriterPipeThread.start();
72          return readerWriterPipeThread;
73      }
74  
75      /**
76       * 
77       * @param reader
78       * @param writer
79       *    may be null TBC: does this make sense? 
80       */
81      private ReaderWriterPipeThread(final Reader reader, final Writer writer) {
82          this.reader = reader;
83          this.writer = writer;
84      }
85  
86      @Override
87      public void run() {
88          while (!interrupted()) {
89              int len;
90              try {
91                  len = this.reader.read(BUF);
92              } catch (final IOException e) {
93                  LOG.error("Error when reading from reader", e);
94                  throw new OctaveIOException(e);
95              }
96              if (len == -1) {
97                  break;
98              }
99              try {
100                 synchronized (this) {
101                     if (this.writer != null) {
102                 	this.writer.write(BUF, 0, len);
103                 	this.writer.flush();
104                     }
105                 }
106             } catch (final IOException e) {
107                 LOG.error("Error when writing to writer", e);
108                 throw new OctaveIOException(e);
109             }
110         }
111         LOG.debug("ReaderWriterPipeThread finished without error");
112     }
113 
114     /**
115      * @param writer
116      *    the writer to set
117      *    This may be null TBC 
118      */
119     public void setWriter(final Writer writer) {
120         synchronized (this) {
121             this.writer = writer;
122         }
123     }
124 
125     /**
126      * Close the thread.
127      */
128     public void close() {
129         interrupt();
130         try {
131             join();
132         } catch (final InterruptedException e) {
133             throw new OctaveInterruptedException(e);
134         }
135     }
136 
137 }