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.client;
30  
31  import java.io.OutputStream;
32  import java.io.IOException;
33  
34  import uk.ac.rdg.resc.jstyx.StyxUtils;
35  import uk.ac.rdg.resc.jstyx.StyxException;
36  
37  /***
38   * Output stream for writing data to a Styx File.  The file will be truncated
39   * at the end of the data that are written through this class.
40   * 
41   * @author Jon Blower
42   * $Revision: 507 $
43   * $Date: 2005-12-01 08:21:56 +0000 (Thu, 01 Dec 2005) $
44   * $Log$
45   * Revision 1.4  2005/12/01 08:21:55  jonblower
46   * Fixed javadoc comments
47   *
48   * Revision 1.3  2005/10/14 18:04:33  jonblower
49   * Fixed bug with not updating file offset, and added code to write zero bytes to signify EOF
50   *
51   * Revision 1.2  2005/09/01 17:12:10  jonblower
52   * Changes to Input and Output stream code
53   *
54   * Revision 1.1  2005/08/31 17:03:18  jonblower
55   * Renamed "StyxFile*putStream*" to "CStyxFile*putStream*" for consistency with CStyxFile class
56   * 
57   * Revision 1.4  2005/05/23 16:48:17  jonblower
58   * Overhauled CStyxFile (esp. asynchronous methods) and StyxConnection (added cache of CStyxFiles)
59   * 
60   * Revision 1.3  2005/05/12 07:40:52  jonblower
61   * CStyxFile.close() no longer throws a StyxException
62   * 
63   * Revision 1.2  2005/03/16 17:55:53  jonblower
64   * Replaced use of java.nio.ByteBuffer with MINA's ByteBuffer to minimise copying of buffers
65   * 
66   * Revision 1.1.1.1  2005/02/16 18:58:19  jonblower
67   * Initial import
68   */
69  public class CStyxFileOutputStream extends OutputStream
70  {
71      
72      private CStyxFile file; // The file to which we are writing
73      private byte[] buf;     // Buffer for storing the results of the last write
74      private int pos;        // Current position in the buffer
75      private long offset;    // The current position in the file
76      private boolean closeConnectionWhenCloseStream; // If this is true, we shall close the underlying
77          // StyxConnection when this stream is closed (this is normally set when
78          // getting an output stream through the StyxURLConnection class)
79      
80      /***
81       * Creates a new CStyxFileOutputStream to write data to the given CStyxFile.
82       * If the file already exists it will be overwritten.
83       * @param file the file to write to
84       * @param closeConnectionWhenCloseStream If this is true, we shall close the underlying
85       * StyxConnection when this stream is closed (this is normally set when
86       * getting an output stream through the StyxURLConnection class)
87       * @todo Add flag to prevent overwriting in certain cases?
88       */
89      public CStyxFileOutputStream(CStyxFile file, boolean closeConnectionWhenCloseStream) throws StyxException
90      {
91          if (file == null)
92          {
93              throw new NullPointerException("file cannot be null");
94          }
95          this.file = file;
96          this.file.openOrCreate(false, StyxUtils.OWRITE | StyxUtils.OTRUNC);
97          this.buf = new byte[(int)this.file.getIoUnit()];
98          this.pos = 0;
99          this.offset = 0;
100         this.closeConnectionWhenCloseStream = closeConnectionWhenCloseStream;
101     }
102     
103     /***
104      * Creates a new CStyxFileOutputStream to write data to the given CStyxFile.
105      * If the file already exists it will be overwritten.
106      * @todo Add flag to prevent overwriting in certain cases?
107      */
108     public CStyxFileOutputStream(CStyxFile file) throws StyxException
109     {
110         this(file, false);
111     }
112     
113     /***
114      * Writes the specified byte to the Styx file.  Must call flush() to
115      * guarantee that the byte is actually written, as it may be held in a 
116      * buffer.
117      */
118     public synchronized void write(int b) throws IOException
119     {
120         // Put the byte in the output buffer
121         this.buf[this.pos] = (byte)b;
122         this.pos++;
123         // If the buffer is full, flush it (i.e. write the data to the output file)
124         if (this.pos >= this.buf.length)
125         {
126             this.flush();
127         }
128     }
129     
130     /***
131      * Flushes the internal buffer and forces any buffered output bytes to be
132      * written
133      */
134     public synchronized void flush() throws IOException
135     {
136         // Write the contents of the buffer to the file
137         try
138         {
139             this.file.write(this.buf, 0, pos, this.offset, true);
140             // Update the offset of the file
141             this.offset += pos;
142             // Reset the pointer position
143             this.pos = 0;
144         }
145         catch(StyxException se)
146         {
147             throw new IOException(se.getMessage());
148         }
149     }
150     
151     /***
152      * Closes the file stream (i.e. clunks the fid of the underlying file) and
153      * flushes any remaining data to the file.
154      */
155     public synchronized void close() throws IOException
156     {
157         // Write all remaining bytes in the buffer
158         this.flush();
159         
160         // Write an empty message to signify end-of-file
161         this.flush();
162         
163         this.file.close();
164         if (this.closeConnectionWhenCloseStream)
165         {
166             this.file.getConnection().close();
167         }
168     }
169 }