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