View Javadoc

1   // ========================================================================
2   // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
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   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.io.nio;
16  
17  import java.io.File;
18  import java.io.FileInputStream;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.OutputStream;
22  import java.nio.ByteBuffer;
23  import java.nio.channels.Channels;
24  import java.nio.channels.FileChannel;
25  import java.nio.channels.ReadableByteChannel;
26  import java.nio.channels.WritableByteChannel;
27  
28  import org.mortbay.io.AbstractBuffer;
29  import org.mortbay.io.Buffer;
30  
31  /* ------------------------------------------------------------------------------- */
32  /** 
33   * 
34   * @author gregw
35   */
36  public class NIOBuffer extends AbstractBuffer
37  {
38    	public final static boolean 
39    		DIRECT=true,
40    		INDIRECT=false;
41    	
42      protected ByteBuffer _buf;
43      private ReadableByteChannel _in;
44      private InputStream _inStream;
45      private WritableByteChannel _out;
46      private OutputStream _outStream;
47  
48      public NIOBuffer(int size, boolean direct)
49      {
50          super(READWRITE,NON_VOLATILE);
51          _buf = direct
52          	?ByteBuffer.allocateDirect(size)
53          	:ByteBuffer.allocate(size);
54          _buf.position(0);
55          _buf.limit(_buf.capacity());
56      }
57      
58      public NIOBuffer(ByteBuffer buffer,boolean immutable)
59      {
60          super(immutable?IMMUTABLE:READWRITE,NON_VOLATILE);
61          _buf = buffer;
62          setGetIndex(buffer.position());
63          setPutIndex(buffer.limit());
64      }
65  
66      /**
67       * @param file
68       */
69      public NIOBuffer(File file) throws IOException
70      {
71          super(READONLY,NON_VOLATILE);
72          FileInputStream fis = new FileInputStream(file);
73          FileChannel fc = fis.getChannel();
74          _buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
75          setGetIndex(0);
76          setPutIndex((int)file.length());
77          _access=IMMUTABLE;
78      }
79  
80      public byte[] array()
81      {
82          if (!_buf.hasArray())
83              return null;
84          return _buf.array();
85      }
86      
87      public int capacity()
88      {
89          return _buf.capacity();
90      }
91  
92      public byte peek(int position)
93      {
94          return _buf.get(position);
95      }
96  
97      public int peek(int index, byte[] b, int offset, int length)
98      {
99          int l = length;
100         if (index+l > capacity())
101         {
102             l=capacity()-index;
103             if (l==0)
104                 return -1;
105         }
106         
107         if (l < 0) 
108             return -1;
109         try
110         {
111             _buf.position(index);
112             _buf.get(b,offset,l);
113         }
114         finally
115         {
116             _buf.position(0);
117         }
118         
119         return l;
120     }
121 
122     public void poke(int index, byte b)
123     {
124         if (isReadOnly()) throw new IllegalStateException(__READONLY);
125         if (index < 0) throw new IllegalArgumentException("index<0: " + index + "<0");
126         if (index > capacity())
127                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
128         _buf.put(index,b);
129     }
130 
131     public int poke(int index, Buffer src)
132     {
133         if (isReadOnly()) throw new IllegalStateException(__READONLY);
134 
135         byte[] array=src.array();
136         if (array!=null)
137         {
138             int length = poke(index,array,src.getIndex(),src.length());
139             return length;
140         }
141         else
142         {
143             Buffer src_buf=src.buffer();
144             if (src_buf instanceof NIOBuffer)
145             {
146                 ByteBuffer src_bytebuf = ((NIOBuffer)src_buf)._buf;
147                 if (src_bytebuf==_buf)
148                     src_bytebuf=_buf.duplicate();
149                 try
150                 {   
151                     _buf.position(index);
152                     int space = _buf.remaining();
153                     
154                     int length=src.length();
155                     if (length>space)    
156                         length=space;
157                     
158                     src_bytebuf.position(src.getIndex());
159                     src_bytebuf.limit(src.getIndex()+length);
160                     
161                     _buf.put(src_bytebuf);
162                     return length;
163                 }
164                 finally
165                 {
166                     _buf.position(0);
167                     src_bytebuf.limit(src_bytebuf.capacity());
168                     src_bytebuf.position(0);
169                 }
170             }
171             else
172                 return super.poke(index,src);
173         }
174     }
175     
176     public int poke(int index, byte[] b, int offset, int length)
177     {
178         if (isReadOnly()) throw new IllegalStateException(__READONLY);
179 
180         if (index < 0) throw new IllegalArgumentException("index<0: " + index + "<0");
181 
182         if (index + length > capacity())
183         {
184             length=capacity()-index;
185             if (length<0)
186                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
187         }
188 
189         try
190         {
191             _buf.position(index);
192             
193             int space=_buf.remaining();
194             
195             if (length>space)
196                 length=space;
197             if (length>0)
198                 _buf.put(b,offset,length);
199             return length;
200         }
201         finally
202         {
203             _buf.position(0);
204         }
205     }
206     
207     /* ------------------------------------------------------------ */
208     public ByteBuffer getByteBuffer()
209     {
210         return _buf;
211     }
212 
213     /* ------------------------------------------------------------ */
214     public int readFrom(InputStream in, int max) throws IOException
215     {
216         if (_in==null || !_in.isOpen() || in!=_inStream)
217         {
218             _in=Channels.newChannel(in);
219             _inStream=in;
220         }
221 
222         if (max<0 || max>space())
223             max=space();
224         int p = putIndex();
225         
226         try
227         {
228             int len=0, total=0, available=max;
229             int loop=0;
230             while (total<max) 
231             {
232                 _buf.position(p);
233                 _buf.limit(p+available);
234                 len=_in.read(_buf);
235                 if (len<0)
236                 {
237                     _in=null;
238                     _inStream=in;
239                     break;
240                 }
241                 else if (len>0)
242                 {
243                     p += len;
244                     total += len;
245                     available -= len;
246                     setPutIndex(p);
247                     loop=0;
248                 }
249                 else if (loop++>1)
250                     break;
251                 if (in.available()<=0)
252                     break;
253             }
254             if (len<0 && total==0)
255                 return -1;
256             return total;
257             
258         }
259         catch(IOException e)
260         {
261             _in=null;
262             _inStream=in;
263             throw e;
264         }
265         finally
266         {
267             if (_in!=null && !_in.isOpen())
268             {
269                 _in=null;
270                 _inStream=in;
271             }
272             _buf.position(0);
273             _buf.limit(_buf.capacity());
274         }
275     }
276 
277     /* ------------------------------------------------------------ */
278     public void writeTo(OutputStream out) throws IOException
279     {
280         if (_out==null || !_out.isOpen() || _out!=_outStream)
281         {
282             _out=Channels.newChannel(out);
283             _outStream=out;
284         }
285 
286         try
287         {
288             int loop=0;
289             while(hasContent() && _out.isOpen())
290             {
291                 _buf.position(getIndex());
292                 _buf.limit(putIndex());
293                 int len=_out.write(_buf);
294                 if (len<0)
295                     break;
296                 else if (len>0)
297                 {
298                     skip(len);
299                     loop=0;
300                 }
301                 else if (loop++>1)
302                     break;
303             }
304         }
305         catch(IOException e)
306         {
307             _out=null;
308             _outStream=null;
309             throw e;
310         }
311         finally
312         {
313             if (_out!=null && !_out.isOpen())
314             {
315                 _out=null;
316                 _outStream=null;
317             }
318             _buf.position(0);
319             _buf.limit(_buf.capacity());
320         }
321         
322     }
323     
324     
325 }