View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.io.nio;
15  
16  import java.io.IOException;
17  import java.net.InetSocketAddress;
18  import java.net.Socket;
19  import java.nio.ByteBuffer;
20  import java.nio.channels.ByteChannel;
21  import java.nio.channels.GatheringByteChannel;
22  import java.nio.channels.SelectableChannel;
23  import java.nio.channels.SocketChannel;
24  
25  import org.eclipse.jetty.io.Buffer;
26  import org.eclipse.jetty.io.EndPoint;
27  import org.eclipse.jetty.util.StringUtil;
28  import org.eclipse.jetty.util.log.Log;
29  
30  
31  /**
32   * 
33   *
34   * To change the template for this generated type comment go to
35   * Window - Preferences - Java - Code Generation - Code and Comments
36   */
37  public class ChannelEndPoint implements EndPoint
38  {
39      protected final ByteChannel _channel;
40      protected final ByteBuffer[] _gather2=new ByteBuffer[2];
41      protected Socket _socket;
42      protected InetSocketAddress _local;
43      protected InetSocketAddress _remote;
44      
45      /**
46       * 
47       */
48      public ChannelEndPoint(ByteChannel channel)
49      {
50          super();
51          this._channel = channel;
52          if (channel instanceof SocketChannel)
53              _socket=((SocketChannel)channel).socket();
54      }
55      
56      public boolean isBlocking()
57      {
58          return  !(_channel instanceof SelectableChannel) || ((SelectableChannel)_channel).isBlocking();
59      }
60      
61      public boolean blockReadable(long millisecs) throws IOException
62      {
63          return true;
64      }
65      
66      public boolean blockWritable(long millisecs) throws IOException
67      {
68          return true;
69      }
70  
71      /* 
72       * @see org.eclipse.io.EndPoint#isOpen()
73       */
74      public boolean isOpen()
75      {
76          return _channel.isOpen();
77      }
78  
79      /* (non-Javadoc)
80       * @see org.eclipse.io.EndPoint#close()
81       */
82      public void close() throws IOException
83      {
84          if (_channel.isOpen())
85          {
86              try
87              {
88                  if (_channel instanceof SocketChannel)
89                  {
90                      // TODO - is this really required?
91                      Socket socket= ((SocketChannel)_channel).socket();
92                      if (!socket.isClosed()&&!socket.isOutputShutdown())
93                          socket.shutdownOutput();
94                  }
95              }
96              catch(IOException e)
97              {
98                  Log.ignore(e);
99              }
100             catch(UnsupportedOperationException e)
101             {
102                 Log.ignore(e);
103             }
104             finally
105             {
106                 _channel.close();
107             }
108         }
109     }
110 
111     /* (non-Javadoc)
112      * @see org.eclipse.io.EndPoint#fill(org.eclipse.io.Buffer)
113      */
114     public int fill(Buffer buffer) throws IOException
115     {
116         Buffer buf = buffer.buffer();
117         int len=0;
118         if (buf instanceof NIOBuffer)
119         {
120             final NIOBuffer nbuf = (NIOBuffer)buf;
121             final ByteBuffer bbuf=nbuf.getByteBuffer();
122             //noinspection SynchronizationOnLocalVariableOrMethodParameter
123             synchronized(bbuf)
124             {
125                 try
126                 {
127                     bbuf.position(buffer.putIndex());
128                     len=_channel.read(bbuf);
129                     if (len<0)
130                         _channel.close();
131                 }
132                 finally
133                 {
134                     buffer.setPutIndex(bbuf.position());
135                     bbuf.position(0);
136                 }
137             }
138         }
139         else
140         {
141             throw new IOException("Not Implemented");
142         }
143         
144         return len;
145     }
146 
147     /* (non-Javadoc)
148      * @see org.eclipse.io.EndPoint#flush(org.eclipse.io.Buffer)
149      */
150     public int flush(Buffer buffer) throws IOException
151     {
152         Buffer buf = buffer.buffer();
153         int len=0;
154         if (buf instanceof NIOBuffer)
155         {
156             final NIOBuffer nbuf = (NIOBuffer)buf;
157             final ByteBuffer bbuf=nbuf.getByteBuffer();
158 
159             //noinspection SynchronizationOnLocalVariableOrMethodParameter
160             synchronized(bbuf)
161             {
162                 try
163                 {
164                     bbuf.position(buffer.getIndex());
165                     bbuf.limit(buffer.putIndex());
166                     len=_channel.write(bbuf);
167                 }
168                 finally
169                 {
170                     if (len>0)
171                         buffer.skip(len);
172                     bbuf.position(0);
173                     bbuf.limit(bbuf.capacity());
174                 }
175             }
176         }
177         else if (buf instanceof RandomAccessFileBuffer)
178         {
179             len = buffer.length();
180             ((RandomAccessFileBuffer)buf).writeTo(_channel,buffer.getIndex(),buffer.length());
181             if (len>0)
182                 buffer.skip(len);
183         }
184         else if (buffer.array()!=null)
185         {
186             ByteBuffer b = ByteBuffer.wrap(buffer.array(), buffer.getIndex(), buffer.length());
187             len=_channel.write(b);
188             if (len>0)
189                 buffer.skip(len);
190         }
191         else
192         {
193             throw new IOException("Not Implemented");
194         }
195         return len;
196     }
197 
198     /* (non-Javadoc)
199      * @see org.eclipse.io.EndPoint#flush(org.eclipse.io.Buffer, org.eclipse.io.Buffer, org.eclipse.io.Buffer)
200      */
201     public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
202     {
203         int length=0;
204 
205         Buffer buf0 = header==null?null:header.buffer();
206         Buffer buf1 = buffer==null?null:buffer.buffer();
207         
208         if (_channel instanceof GatheringByteChannel &&
209             header!=null && header.length()!=0 && buf0 instanceof NIOBuffer && 
210             buffer!=null && buffer.length()!=0 && buf1 instanceof NIOBuffer)
211         {
212             final NIOBuffer nbuf0 = (NIOBuffer)buf0;
213             final ByteBuffer bbuf0=nbuf0.getByteBuffer();
214             final NIOBuffer nbuf1 = (NIOBuffer)buf1;
215             final ByteBuffer bbuf1=nbuf1.getByteBuffer();
216 
217             synchronized(this)
218             {
219                 // We must sync because buffers may be shared (eg nbuf1 is likely to be cached content).
220                 //noinspection SynchronizationOnLocalVariableOrMethodParameter
221                 synchronized(bbuf0)
222                 {
223                     //noinspection SynchronizationOnLocalVariableOrMethodParameter
224                     synchronized(bbuf1)
225                     {
226                         try
227                         {
228                             // Adjust position indexs of buf0 and buf1
229                             bbuf0.position(header.getIndex());
230                             bbuf0.limit(header.putIndex());
231                             bbuf1.position(buffer.getIndex());
232                             bbuf1.limit(buffer.putIndex());
233 
234                             _gather2[0]=bbuf0;
235                             _gather2[1]=bbuf1;
236 
237                             // do the gathering write.
238                             length=(int)((GatheringByteChannel)_channel).write(_gather2);
239                             
240                             int hl=header.length();
241                             if (length>hl)
242                             {
243                                 header.clear();
244                                 buffer.skip(length-hl);
245                             }
246                             else if (length>0)
247                             {
248                                 header.skip(length);
249                             }
250                             
251                         }
252                         finally
253                         {
254                             // adjust buffer 0 and 1
255                             if (!header.isImmutable())
256                                 header.setGetIndex(bbuf0.position());
257                             if (!buffer.isImmutable())
258                                 buffer.setGetIndex(bbuf1.position());
259 
260                             bbuf0.position(0);
261                             bbuf1.position(0);
262                             bbuf0.limit(bbuf0.capacity());
263                             bbuf1.limit(bbuf1.capacity());
264                         }
265                     }
266                 }
267             }
268         }
269         else
270         {
271             // TODO - consider copying buffers buffer and trailer into header if there is space!
272             
273             // flush header
274             if (header!=null && header.length()>0)
275                 length=flush(header);
276 
277             // flush buffer
278             if ((header==null || header.length()==0) &&
279                  buffer!=null && buffer.length()>0)
280                 length+=flush(buffer);
281 
282             // flush trailer
283             if ((header==null || header.length()==0) &&
284                 (buffer==null || buffer.length()==0) &&
285                  trailer!=null && trailer.length()>0)
286                 length+=flush(trailer);
287         }
288         
289         return length;
290     }
291 
292     /**
293      * @return Returns the channel.
294      */
295     public ByteChannel getChannel()
296     {
297         return _channel;
298     }
299 
300 
301     /* ------------------------------------------------------------ */
302     /* 
303      * @see org.eclipse.io.EndPoint#getLocalAddr()
304      */
305     public String getLocalAddr()
306     {
307         if (_socket==null)
308             return null;
309         
310         if (_local==null)
311             _local=(InetSocketAddress)_socket.getLocalSocketAddress();
312         
313        if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
314            return StringUtil.ALL_INTERFACES;
315         
316         return _local.getAddress().getHostAddress();
317     }
318 
319     /* ------------------------------------------------------------ */
320     /* 
321      * @see org.eclipse.io.EndPoint#getLocalHost()
322      */
323     public String getLocalHost()
324     {
325         if (_socket==null)
326             return null;
327         
328         if (_local==null)
329             _local=(InetSocketAddress)_socket.getLocalSocketAddress();
330         
331        if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
332            return StringUtil.ALL_INTERFACES;
333         
334         return _local.getAddress().getCanonicalHostName();
335     }
336 
337     /* ------------------------------------------------------------ */
338     /* 
339      * @see org.eclipse.io.EndPoint#getLocalPort()
340      */
341     public int getLocalPort()
342     {
343         if (_socket==null)
344             return 0;
345         
346         if (_local==null)
347             _local=(InetSocketAddress)_socket.getLocalSocketAddress();
348         if (_local==null)
349             return -1;
350         return _local.getPort();
351     }
352 
353     /* ------------------------------------------------------------ */
354     /* 
355      * @see org.eclipse.io.EndPoint#getRemoteAddr()
356      */
357     public String getRemoteAddr()
358     {
359         if (_socket==null)
360             return null;
361         
362         if (_remote==null)
363             _remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
364         
365         if (_remote==null)
366             return null;
367         return _remote.getAddress().getHostAddress();
368     }
369 
370     /* ------------------------------------------------------------ */
371     /* 
372      * @see org.eclipse.io.EndPoint#getRemoteHost()
373      */
374     public String getRemoteHost()
375     {
376         if (_socket==null)
377             return null;
378         
379         if (_remote==null)
380             _remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
381 
382         if (_remote==null)
383             return null;
384         return _remote.getAddress().getCanonicalHostName();
385     }
386 
387     /* ------------------------------------------------------------ */
388     /* 
389      * @see org.eclipse.io.EndPoint#getRemotePort()
390      */
391     public int getRemotePort()
392     {
393         if (_socket==null)
394             return 0;
395         
396         if (_remote==null)
397             _remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
398 
399         return _remote==null?-1:_remote.getPort();
400     }
401 
402     /* ------------------------------------------------------------ */
403     /* 
404      * @see org.eclipse.io.EndPoint#getConnection()
405      */
406     public Object getTransport()
407     {
408         return _channel;
409     }
410 
411     /* ------------------------------------------------------------ */
412     public void flush()
413         throws IOException
414     {   
415     }
416 
417     /* ------------------------------------------------------------ */
418     public boolean isBufferingInput()
419     {
420         return false;
421     }
422 
423     /* ------------------------------------------------------------ */
424     public boolean isBufferingOutput()
425     {
426         return false;
427     }
428 
429     /* ------------------------------------------------------------ */
430     public boolean isBufferred()
431     {
432         return false;
433     }
434 }