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