1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package uk.ac.rdg.resc.jstyx.gridservice.client;
30
31 import javax.swing.JFrame;
32
33 import java.awt.event.WindowAdapter;
34 import java.awt.event.WindowEvent;
35
36 import java.io.InputStream;
37 import java.io.FileInputStream;
38 import java.io.FileNotFoundException;
39 import java.io.IOException;
40
41 import org.apache.mina.common.ByteBuffer;
42
43 import uk.ac.rdg.resc.jstyx.client.CStyxFile;
44
45 /***
46 * Class representing a viewer for an output stream from a Styx Grid Service
47 * instance. Subclasses only need to implement the <code>newDataArrived()</code>
48 * method, which is called when new data are read from the stream. Subclasses
49 * <i>may</i> override <code>eof</code> (which is called when end-of-stream is
50 * reached) and <code>streamError</code> (which is called if an error occurs).
51 * See <code>TextStreamViewer</code> for an example of a very simple StreamViewer.
52 *
53 * @author Jon Blower
54 * $Revision: 335 $
55 * $Date: 2005-08-01 17:38:05 +0100 (Mon, 01 Aug 2005) $
56 * $Log$
57 * Revision 1.8 2005/08/01 16:38:05 jonblower
58 * Implemented simple parameter handling
59 *
60 * Revision 1.7 2005/06/13 13:55:42 jonblower
61 * Adapted LB viewer for JStyx framework
62 *
63 * Revision 1.6 2005/06/10 07:54:49 jonblower
64 * Added code to convert event-based StreamViewer to InputStream-based one
65 *
66 * Revision 1.5 2005/05/27 21:22:39 jonblower
67 * Further development of caching stream readers
68 *
69 * Revision 1.4 2005/05/27 17:05:07 jonblower
70 * Changes to incorporate GeneralCachingStreamReader
71 *
72 * Revision 1.3 2005/05/27 07:44:07 jonblower
73 * Continuing to implement Stream viewers
74 *
75 * Revision 1.2 2005/05/26 21:33:40 jonblower
76 * Added method for viewing streams in a window
77 *
78 * Revision 1.1 2005/05/26 16:47:43 jonblower
79 * Initial import
80 *
81 */
82 public abstract class StreamViewer extends JFrame
83 {
84 protected CachedStreamReader reader;
85 protected long offset;
86 protected boolean started;
87
88 protected InputStream is;
89
90 public StreamViewer()
91 {
92 this.offset = 0;
93 this.started = false;
94 this.is = null;
95 this.addWindowListener(new WindowAdapter()
96 {
97
98 public void windowClosing(WindowEvent we)
99 {
100 stop();
101 }
102 });
103 }
104
105 /***
106 * Sets the CStyxFile that represents the stream
107 */
108 public void setStreamReader(CachedStreamReader reader)
109 {
110 this.reader = reader;
111 this.setTitle(reader.getName());
112 }
113
114 /***
115 * Sends a message to start reading from the stream and makes the GUI visible.
116 * If we have already started reading from the stream, this does nothing.
117 */
118 public void start()
119 {
120 this.setVisible(true);
121 if (!this.started)
122 {
123 this.started = true;
124 this.reader.read(this, this.offset, 8192);
125 }
126 }
127
128 /***
129 * Sends a message to stop reading from this stream. The stream position will
130 * not be reset: use reset() for this. After calling this, we can continue
131 * reading from the stream by calling start(). Note that one more chunk of
132 * data might arrive after calling this (if there was a read message outstanding
133 * at the time of calling this).
134 */
135 public void stop()
136 {
137 if (this.started)
138 {
139 this.started = false;
140 }
141 }
142
143 /***
144 * Sets the position of the stream to the given offset (i.e. number of bytes
145 * after the beginning of the file).
146 */
147 public void setPosition(long pos)
148 {
149 this.offset = pos;
150 }
151
152 /***
153 * Gets the current position of the stream (i.e. the position of the next
154 * byte that will arrive)
155 */
156 public long getPosition()
157 {
158 return this.offset;
159 }
160
161 /***
162 * Resets the stream to the start, so we can start reading from the beginning
163 * again. Exactly equivalent to <code>setPosition(0)</code>
164 */
165 public void reset()
166 {
167 this.setPosition(0);
168 }
169
170 /***
171 * Called when new data arrive from the server
172 */
173 public abstract void newDataArrived(byte[] data, int size);
174
175 /***
176 * Called by CachedStreamReader when a chunk of data is read from stream
177 */
178 public final void newData(byte[] data, int size)
179 {
180 if (size > 0)
181 {
182 this.offset += size;
183 this.newDataArrived(data, size);
184 if (this.is != null)
185 {
186 synchronized (this.is)
187 {
188 this.is.notifyAll();
189 }
190 }
191 this.reader.read(this, this.offset, 8192);
192 }
193 else
194 {
195 System.err.println("Reached EOF");
196 }
197 }
198
199 public void readError(Exception e)
200 {
201 e.printStackTrace();
202 }
203
204 /***
205 * @return An InputStream that can be used to read from this stream. This
206 * InputStream <b>must</b> be consumed in a separate thread to avoid blocking.
207 */
208 public InputStream getInputStream()
209 {
210 if (this.is == null)
211 {
212 this.is = new StyxStream();
213 }
214 return this.is;
215 }
216
217 /***
218 * An InputStream for reading from the Styx stream. This InputStream <b>must</b>
219 * be consumed in a separate thread to avoid blocking
220 */
221 private class StyxStream extends InputStream
222 {
223 private long pos = 0;
224 private FileInputStream in;
225
226 public StyxStream()
227 {
228 try
229 {
230 this.in = new FileInputStream(reader.getCacheFile());
231 }
232 catch(Exception e)
233 {
234 e.printStackTrace();
235 }
236 }
237
238 public synchronized int read() throws IOException
239 {
240 try
241 {
242 int b;
243 do
244 {
245
246 b = this.in.read();
247 if (b < 0)
248 {
249
250 if (reader.isEOF())
251 {
252 System.err.println("EOF in cache file");
253 return -1;
254 }
255
256
257 this.wait();
258 }
259 } while (b < 0);
260 return b;
261 }
262 catch(InterruptedException ie)
263 {
264 ie.printStackTrace();
265 return -1;
266 }
267 }
268
269 public synchronized void close() throws IOException
270 {
271 if (this.in != null)
272 {
273 this.in.close();
274 }
275 }
276 }
277
278 }