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             // TODO - consider copying buffers buffer and trailer into header if there is space!
266             
267             // flush header
268             if (header!=null && header.length()>0)
269                 length=flush(header);
270 
271             // flush buffer
272             if ((header==null || header.length()==0) &&
273                  buffer!=null && buffer.length()>0)
274                 length+=flush(buffer);
275 
276             // flush trailer
277             if ((header==null || header.length()==0) &&
278                 (buffer==null || buffer.length()==0) &&
279                  trailer!=null && trailer.length()>0)
280                 length+=flush(trailer);
281         }
282         
283         return length;
284     }
285 
286     /**
287      * @return Returns the channel.
288      */
289     public ByteChannel getChannel()
290     {
291         return _channel;
292     }
293 
294 
295     /* ------------------------------------------------------------ */
296     /* 
297      * @see org.mortbay.io.EndPoint#getLocalAddr()
298      */
299     public String getLocalAddr()
300     {
301         if (_socket==null)
302             return null;
303         
304         if (_local==null)
305             _local=(InetSocketAddress)_socket.getLocalSocketAddress();
306         
307        if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
308            return Portable.ALL_INTERFACES;
309         
310         return _local.getAddress().getHostAddress();
311     }
312 
313     /* ------------------------------------------------------------ */
314     /* 
315      * @see org.mortbay.io.EndPoint#getLocalHost()
316      */
317     public String getLocalHost()
318     {
319         if (_socket==null)
320             return null;
321         
322         if (_local==null)
323             _local=(InetSocketAddress)_socket.getLocalSocketAddress();
324         
325        if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
326            return Portable.ALL_INTERFACES;
327         
328         return _local.getAddress().getCanonicalHostName();
329     }
330 
331     /* ------------------------------------------------------------ */
332     /* 
333      * @see org.mortbay.io.EndPoint#getLocalPort()
334      */
335     public int getLocalPort()
336     {
337         if (_socket==null)
338             return 0;
339         
340         if (_local==null)
341             _local=(InetSocketAddress)_socket.getLocalSocketAddress();
342         if (_local==null)
343             return -1;
344         return _local.getPort();
345     }
346 
347     /* ------------------------------------------------------------ */
348     /* 
349      * @see org.mortbay.io.EndPoint#getRemoteAddr()
350      */
351     public String getRemoteAddr()
352     {
353         if (_socket==null)
354             return null;
355         
356         if (_remote==null)
357             _remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
358         
359         if (_remote==null)
360             return null;
361         return _remote.getAddress().getHostAddress();
362     }
363 
364     /* ------------------------------------------------------------ */
365     /* 
366      * @see org.mortbay.io.EndPoint#getRemoteHost()
367      */
368     public String getRemoteHost()
369     {
370         if (_socket==null)
371             return null;
372         
373         if (_remote==null)
374             _remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
375         
376         return _remote.getAddress().getCanonicalHostName();
377     }
378 
379     /* ------------------------------------------------------------ */
380     /* 
381      * @see org.mortbay.io.EndPoint#getRemotePort()
382      */
383     public int getRemotePort()
384     {
385         if (_socket==null)
386             return 0;
387         
388         if (_remote==null)
389             _remote=(InetSocketAddress)_socket.getRemoteSocketAddress();
390         
391         return _remote==null?-1:_remote.getPort();
392     }
393 
394     /* ------------------------------------------------------------ */
395     /* 
396      * @see org.mortbay.io.EndPoint#getConnection()
397      */
398     public Object getTransport()
399     {
400         return _channel;
401     }
402 
403     /* ------------------------------------------------------------ */
404     public void flush()
405         throws IOException
406     {   
407     }
408 
409     /* ------------------------------------------------------------ */
410     public boolean isBufferingInput()
411     {
412         return false;
413     }
414 
415     /* ------------------------------------------------------------ */
416     public boolean isBufferingOutput()
417     {
418         return false;
419     }
420 
421     /* ------------------------------------------------------------ */
422     public boolean isBufferred()
423     {
424         return false;
425     }
426 }