View Javadoc

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