Package com.aelitis.azureus.core.clientmessageservice.impl

Source Code of com.aelitis.azureus.core.clientmessageservice.impl.NonBlockingReadWriteService

/*
* Created on Nov 3, 2005
* Created by Alon Rohter
* Copyright (C) 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package com.aelitis.azureus.core.clientmessageservice.impl;

import java.nio.channels.SocketChannel;
import java.util.*;

import org.gudy.azureus2.core3.util.*;

import com.aelitis.azureus.core.networkmanager.VirtualChannelSelector;
import com.aelitis.azureus.core.peermanager.messaging.Message;
import com.aelitis.azureus.core.peermanager.messaging.azureus.AZGenericMapPayload;


/**
*
*/
public class NonBlockingReadWriteService {
 
  private final VirtualChannelSelector read_selector;
  private final VirtualChannelSelector write_selector;
 
  private final ArrayList connections = new ArrayList();
  private final AEMonitor connections_mon = new AEMonitor( "connections" );
 
  private final ServiceListener listener;
  private final String service_name;
  private volatile boolean destroyed;
 
  private long last_timeout_check_time = 0;
  private static final int TIMEOUT_CHECK_INTERVAL_MS = 10*1000//check for timeouts every 10sec
  private final int activity_timeout_period_ms;
  private final int close_delay_period_ms;
 
 
  public NonBlockingReadWriteService( String _service_name, int timeout, ServiceListener _listener ) {
    this( _service_name, timeout, 0, _listener );
  }
 
  public NonBlockingReadWriteService( String _service_name, int timeout, int close_delay, ServiceListener _listener ) {
    this.service_name = _service_name;
    this.listener = _listener;

    read_selector = new VirtualChannelSelector( service_name, VirtualChannelSelector.OP_READ, false );
    write_selector = new VirtualChannelSelector( service_name, VirtualChannelSelector.OP_WRITE, true );

    if( timeout < TIMEOUT_CHECK_INTERVAL_MS /1000 timeout = TIMEOUT_CHECK_INTERVAL_MS /1000;
    this.activity_timeout_period_ms = timeout *1000;
    close_delay_period_ms      = close_delay * 1000;
   
    new AEThread2( "[" +service_name+ "] Service Select", true )
    {
        public void run() {
          while( true ) {
           
            boolean  stop_after_select = destroyed;
           
            if ( stop_after_select ){
              read_selector.destroy();
              write_selector.destroy();
            }
           
            try{
              read_selector.select( 50 );
              write_selector.select( 50 );
            }
            catch( Throwable t ) {
              Debug.out( "[" +service_name+ "] SelectorLoop() EXCEPTION: ", t );
            }
           
            if (stop_after_select){
              break;
            }
           
            doConnectionTimeoutChecks();
           
              // check this at the end so we have one last run through  the selectors to do cancels
              // before exiting
          }
        }
      }.start();
  }
 
 
 
  public void
  destroy()
  {
      try
        connections_mon.enter();
             
        connections.clear();
       
        destroyed  = true;
       
      }finally{
        connections_mon.exit();
      }
  }
 
 
 
  public void addClientConnection( ClientConnection connection ) {
    //add to active list
   
    try connections_mon.enter();
   
      if ( destroyed ){
       
        Debug.out( "connection added after destroy" );
      }
     
      connections.add( connection );
    }finally
      connections_mon.exit();
    }
   
    registerForSelection( connection );
  }
 
 
 
  public void removeClientConnection( ClientConnection connection ) {
    read_selector.cancel( connection.getSocketChannel() );
    write_selector.cancel( connection.getSocketChannel() );
   
    //remove from active list
    try connections_mon.enter();
      connections.remove( connection );
    }
    finally connections_mon.exit()}
  }
 
 
 
 
 
  private void registerForSelection( final ClientConnection client ) {   
    //READS
    VirtualChannelSelector.VirtualSelectorListener read_listener = new VirtualChannelSelector.VirtualSelectorListener() {
      //SUCCESS
      public boolean selectSuccess( VirtualChannelSelector selector, SocketChannel sc, Object attachment ) {      
        try{
          Message[] messages = client.readMessages();
       
          if( messages != null ) {       
            for( int i=0; i < messages.length; i++ ) {
              AZGenericMapPayload msg = (AZGenericMapPayload)messages[i];
              ClientMessage client_msg = new ClientMessage( msg.getID(), client, msg.getMapPayload(), null )//note no handler. we let the listener attach it   
              listener.messageReceived( client_msg )
            }
          } 
         
          return( client.getLastReadMadeProgress());
        }
        catch( Throwable t ) {
          if ( !client.isClosePending()){
           
            //System.out.println( "[" +new Date()+ "] Connection read error [" +sc.socket().getInetAddress()+ "] [" +client.getDebugString()+ "]: " +t.getMessage() );
          }
         
          listener.connectionError( client, t );
          return( false );
        }
      }

      //FAILURE
      public void selectFailure( VirtualChannelSelector selector, SocketChannel sc, Object attachment, Throwable msg ) {
        if ( !destroyed ){
          msg.printStackTrace();
        }
        listener.connectionError( client, msg );
      }
    };
   
   
    //WRITES
    final VirtualChannelSelector.VirtualSelectorListener write_listener = new VirtualChannelSelector.VirtualSelectorListener() {
      public boolean selectSuccess( VirtualChannelSelector selector, SocketChannel sc, Object attachment ) {    
        try{
          boolean more_writes_needed = client.writeMessages();
       
          if( more_writes_needed ) {
            write_selector.resumeSelects( client.getSocketChannel() )//we need to resume since write selects are auto-paused after select op
          }
         
          return( client.getLastWriteMadeProgress());
        }
        catch( Throwable t ) {
          //System.out.println( "[" +new Date()+ "] Connection write error [" +sc.socket().getInetAddress()+ "] [" +client.getDebugString()+ "]: " +t.getMessage() );
          listener.connectionError( client, t );
          return( false );
        }
      }

      public void selectFailure( VirtualChannelSelector selector, SocketChannel sc, Object attachment, Throwable msg ) {
        if ( !destroyed ){
          msg.printStackTrace();
        }
        listener.connectionError( client, msg );
      }
    };

    write_selector.register( client.getSocketChannel(), write_listener, null )//start writing back to the connection
    write_selector.pauseSelects( client.getSocketChannel() );   //wait until we've got something to send before selecting
   
    read_selector.register( client.getSocketChannel(), read_listener, null )//start reading from the connection
  }
 
 
  private void doConnectionTimeoutChecks() {
    //check timeouts
    long time = System.currentTimeMillis();
    if( time < last_timeout_check_time || time - last_timeout_check_time > TIMEOUT_CHECK_INTERVAL_MS ) {
      ArrayList timed_out = new ArrayList();
     
      try connections_mon.enter();
        long current_time = System.currentTimeMillis();
   
        for( int i=0; i < connections.size(); i++ ) {
          ClientConnection vconn = (ClientConnection)connections.get( i );
       
          if( current_time < vconn.getLastActivityTime() ) {  //time went backwards!
            vconn.resetLastActivityTime();
          }
          else{
            if( current_time - vconn.getLastActivityTime() > activity_timeout_period_ms ||
               ( close_delay_period_ms > 0 &&
                 current_time - vconn.getLastActivityTime() > close_delay_period_ms )){
             
              timed_out.add( vconn );   //do actual removal outside the check loop
            }
          }
        }
      }
      finally connections_mon.exit()}
     
      for( int i=0; i < timed_out.size(); i++ ) { 
        ClientConnection vconn = (ClientConnection)timed_out.get( i );
        // don't change the exception text - it is used elsewhere
        listener.connectionError( vconn, new Exception( "Timeout" ));
      }
     
      last_timeout_check_time = System.currentTimeMillis();
    }
  }
 
 

 
 
  public void sendMessage( ClientMessage message ) {
    ClientConnection vconn = message.getClient();
   
    boolean still_connected;
   
    try connections_mon.enter();
      still_connected = connections.contains( vconn );
    }
    finally connections_mon.exit()}
   
    if( !still_connected ) {
      // System.out.println( "[" +new Date()+ "] Connection message send error [connection no longer connected]: " +vconn.getDebugString()+ "]" );
      message.reportFailed( new Exception("No longer connected" ));
      //listener.connectionError( vconn ); //no need to call this, as there is no connection to remove
      return;
    }
   
    Message reply = new AZGenericMapPayload( message.getMessageID(), message.getPayload(), (byte)1 );

    vconn.sendMessage( message, reply );
   
    write_selector.resumeSelects( vconn.getSocketChannel() )//start write selecting now that there's something to send
  }
 
 
 

  public interface ServiceListener {

    public void messageReceived( ClientMessage message );
   
    public void connectionError( ClientConnection connection, Throwable error );
   
  }
 
}
TOP

Related Classes of com.aelitis.azureus.core.clientmessageservice.impl.NonBlockingReadWriteService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.