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.server;
30  
31  import org.apache.log4j.Logger;
32  
33  import org.apache.mina.common.ByteBuffer;
34  
35  import uk.ac.rdg.resc.jstyx.StyxUtils;
36  import uk.ac.rdg.resc.jstyx.StyxException;
37  import uk.ac.rdg.resc.jstyx.types.ULong;
38  
39  /***
40   * File whose underlying data are stored as a ByteBuffer in memory. This buffer
41   * can grow to arbitrary size.
42   *
43   * @author Jon Blower
44   * $Revision: 601 $
45   * $Date: 2006-03-20 17:51:50 +0000 (Mon, 20 Mar 2006) $
46   * $Log$
47   * Revision 1.20  2006/03/20 17:51:50  jonblower
48   * Adding authentication to base JStyx system
49   *
50   * Revision 1.19  2005/09/08 07:08:59  jonblower
51   * Removed "String user" from list of parameters to StyxFile.write()
52   *
53   * Revision 1.18  2005/09/02 16:51:20  jonblower
54   * Fixed bug with ByteBuffers being released prematurely and changed to use autoExpanding ByteBuffers
55   *
56   * Revision 1.17  2005/09/01 07:50:22  jonblower
57   * Trying to fix bug with ByteBuffers being released (can't read from InMemoryFile)
58   *
59   * Revision 1.16  2005/08/30 16:29:00  jonblower
60   * Added processAndReplyRead() helper functions to StyxFile
61   *
62   * Revision 1.13  2005/06/10 07:53:12  jonblower
63   * Changed SGS namespace: removed "inurl" and subsumed functionality into "stdin"
64   *
65   * Revision 1.12  2005/04/28 08:11:15  jonblower
66   * Modified permissions handling in documentation directory of SGS
67   *
68   * Revision 1.10  2005/04/27 16:11:43  jonblower
69   * Added capability to add documentation files to SGS namespace
70   *
71   * Revision 1.9  2005/04/26 07:46:11  jonblower
72   * Continuing to improve setting of parameters in Styx Grid Services
73   *
74   * Revision 1.8  2005/03/24 15:11:07  jonblower
75   * Changed so that underlying ByteBuffer is allocated on the first write to the file
76   *
77   * Revision 1.7  2005/03/24 13:07:09  jonblower
78   * Added code to prevent the file growing to larger than a specified size
79   *
80   * Revision 1.6  2005/03/24 12:55:14  jonblower
81   * Changed to use ByteBuffer as backing store
82   *
83   * Revision 1.5  2005/03/24 09:48:31  jonblower
84   * Changed 'count' from long to int throughout for reading and writing
85   *
86   * Revision 1.4  2005/03/16 17:56:23  jonblower
87   * Replaced use of java.nio.ByteBuffer with MINA's ByteBuffer to minimise copying of buffers
88   *
89   * Revision 1.3  2005/03/11 14:02:16  jonblower
90   * Merged MINA-Test_20059309 into main line of development
91   *
92   * Revision 1.2.2.1  2005/03/10 20:55:38  jonblower
93   * Removed references to Netty
94   *
95   * Revision 1.2  2005/03/01 13:47:43  jonblower
96   * Changed default user and group to 'user' and 'group'
97   *
98   * Revision 1.1.1.1  2005/02/16 18:58:31  jonblower
99   * Initial import
100  *
101  */
102 public class InMemoryFile extends StyxFile
103 {
104     
105     private static final Logger log = Logger.getLogger(InMemoryFile.class);
106     
107     /***
108      * The org.apache.mina.common.ByteBuffer that holds the data exposed by this file.
109      * The first byte of readable data is always at position zero and the number
110      * of valid bytes in the buffer is its limit
111      */
112     protected ByteBuffer buf;
113     
114     /***
115      * Creates a new instance of InMemoryFile
116      */
117     public InMemoryFile(String name, String userID, String groupID,
118         int permissions, boolean isAppendOnly, boolean isExclusive)
119         throws StyxException
120     {
121         super(name, userID, groupID, permissions, isAppendOnly, isExclusive);
122     }
123     
124     public InMemoryFile(String name, int permissions,
125         boolean isAppendOnly, boolean isExclusive)
126         throws StyxException
127     {
128         this(name, "user", "group", permissions, isAppendOnly, isExclusive);
129     }
130     
131     public InMemoryFile(String name, int permissions)
132         throws StyxException
133     {
134         this(name, permissions, false, false);
135     }
136     
137     /***
138      * Creates an InMemoryFile with default permissions (0666, rw-rw-rw-)
139      */
140     public InMemoryFile(String name)
141         throws StyxException
142     {
143         this(name, 0666);
144     }
145     
146     public synchronized void read(StyxFileClient client, long offset, int count,
147         int tag) throws StyxException
148     {
149         if (this.buf != null)
150         {
151             // We must increment the reference count to this buffer because it will
152             // be decremented when the return message is sent.
153             this.buf.acquire();
154         }
155         this.processAndReplyRead(this.buf, client, offset, count, tag);
156     }
157     
158     public synchronized void write(StyxFileClient client, long offset,
159         int count, ByteBuffer data, boolean truncate, int tag)
160         throws StyxException
161     {
162         if (this.buf == null)
163         {
164             // This is the first write to the file; create the buffer.
165             this.buf = ByteBuffer.allocate(count);
166             // Set the buffer to expand automatically in response to writes
167             this.buf.setAutoExpand(true);
168             this.buf.position(0).limit(0);
169             log.debug("Allocated InMemoryFile with capacity " + this.buf.capacity());
170         }
171         if (offset > this.buf.limit())
172         {
173             throw new StyxException("attempt to write past the end of the file");
174         }
175         // Set the position of the buffer
176         this.buf.position((int)offset);
177         // We don't have to worry about the size of the buffer because it will
178         // grow automatically if necessary
179         this.buf.put(data);
180         if (truncate)
181         {
182             this.buf.limit(this.buf.position());
183         }
184         this.replyWrite(client, count, tag);
185     }
186     
187     /***
188      * Set the contents of this file to the given String.
189      */
190     public synchronized void setContents(String newContents)
191     {
192         // Convert the String to bytes
193         byte[] bytes = StyxUtils.strToUTF8(newContents);
194         // Create a buffer if we need to
195         if (this.buf == null)
196         {
197             this.buf = ByteBuffer.allocate(bytes.length);
198             this.buf.setAutoExpand(true);
199             log.debug("Allocated InMemoryFile with capacity " + this.buf.capacity());
200         }
201         // Write the data at the start of the buffer, then set the length
202         this.buf.position(0);
203         // We don't have to worry about the size of the buffer because it will
204         // grow automatically if necessary
205         this.buf.put(bytes);
206         this.buf.limit(bytes.length);
207         // Notify that the contents of the file have changed
208         this.contentsChanged();
209     }
210     
211     public synchronized ULong getLength()
212     {
213         if (this.buf == null)
214         {
215             return ULong.ZERO;
216         }
217         return new ULong(this.buf.limit());
218     }
219     
220     /***
221      * Frees the resources associated with the file (releases the underlying
222      * ByteBuffer back to the pool).  After this is called, the file can no
223      * longer be used.
224      */
225     public synchronized void delete()
226     {
227         if (this.buf != null)
228         {
229             this.buf.release();
230         }
231     }
232     
233     /***
234      * Gets the data in this file as a String
235      */
236     public synchronized String getContents()
237     {
238         if (this.buf == null)
239         {
240             return "";
241         }
242         // Make sure the position is set to zero
243         this.buf.position(0);
244         // The limit will have already been set
245         return StyxUtils.dataToString(this.buf);
246     }
247     
248     public static void main (String[] args) throws Exception
249     {
250         // Create the root directory of the Styx server
251         StyxDirectory root = new StyxDirectory("/");
252         // Add an InMemoryFile to the root
253         root.addChild(new InMemoryFile("inmem"));
254         // Start a StyxServer, listening on port 9876
255         new StyxServer(9876, root).start();
256     }
257     
258 }