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 }