View Javadoc

1   /*
2    * Copyright (c) 2005 The University of Reading
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    * 1. Redistributions of source code must retain the above copyright
9    *    notice, this list of conditions and the following disclaimer.
10   * 2. Redistributions in binary form must reproduce the above copyright
11   *    notice, this list of conditions and the following disclaimer in the
12   *    documentation and/or other materials provided with the distribution.
13   * 3. Neither the name of the University of Reading, nor the names of the
14   *    authors or contributors may be used to endorse or promote products
15   *    derived from this software without specific prior written permission.
16   * 
17   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20   * IN NO EVENT SHALL THE AUTHOR 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  
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              // Stop reading from the stream if the window is closed
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                     // Try reading from the stream
246                     b = this.in.read();
247                     if (b < 0)
248                     {
249                         // Check for EOF in the cache
250                         if (reader.isEOF())
251                         {
252                             System.err.println("EOF in cache file");
253                             return -1;
254                         }
255                         // We're not ready to read from this position yet.
256                         // Wait until we are notified that more data have arrived
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 }