Package com.google.code.hs4j.network.hs

Source Code of com.google.code.hs4j.network.hs.HandlerSocketConnectorImpl$InnerControllerStateListener

/**
*Copyright [2010-2011] [dennis zhuang(killme2008@gmail.com)]
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*             http://www.apache.org/licenses/LICENSE-2.0
*Unless required by applicable law or agreed to in writing,
*software distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
*either express or implied. See the License for the specific language governing permissions and limitations under the License
*/
package com.google.code.hs4j.network.hs;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.code.hs4j.Command;
import com.google.code.hs4j.CommandFactory;
import com.google.code.hs4j.HSClient;
import com.google.code.hs4j.Protocol;
import com.google.code.hs4j.exception.HandlerSocketException;
import com.google.code.hs4j.impl.HSClientImpl;
import com.google.code.hs4j.impl.IndexRecord;
import com.google.code.hs4j.impl.ReconnectRequest;
import com.google.code.hs4j.network.config.Configuration;
import com.google.code.hs4j.network.core.Controller;
import com.google.code.hs4j.network.core.ControllerStateListener;
import com.google.code.hs4j.network.core.EventType;
import com.google.code.hs4j.network.core.Session;
import com.google.code.hs4j.network.core.WriteMessage;
import com.google.code.hs4j.network.nio.NioSession;
import com.google.code.hs4j.network.nio.NioSessionConfig;
import com.google.code.hs4j.network.nio.impl.SocketChannelController;
import com.google.code.hs4j.network.util.SystemUtils;

/**
* Connector implementation
*
* @author dennis
*/
public class HandlerSocketConnectorImpl extends SocketChannelController
    implements HandlerSocketConnector {

  private final DelayQueue<ReconnectRequest> waitingQueue = new DelayQueue<ReconnectRequest>();

  private final ExecutorService openIndexExectur = Executors
      .newCachedThreadPool();

  private volatile long healSessionInterval = 2000L;
  private final int connectionPoolSize; // session pool size
  protected Protocol protocol;

  private volatile boolean allowAutoReconnect = true;

  private final CommandFactory commandFactory;

  private final HSClientImpl hsClient;

  /**
   * When session was created,it must be added to sessionList,but before
   * that,the opening index must reopen on this session.
   *
   * @author dennis
   * @date 2010-11-28
   */
  private final class AddSessionTask implements Runnable {
    private final HandlerSocketSessionImpl session;

    private AddSessionTask(HandlerSocketSessionImpl session) {
      this.session = session;
    }

    public void run() {
      try {
        Map<Integer, IndexRecord> indexMap = HandlerSocketConnectorImpl.this.hsClient
            .getIndexMap();
        if (!indexMap.isEmpty()) {
          for (IndexRecord record : indexMap.values()) {
            try {
              Command cmd = commandFactory
                  .createOpenIndexCommand(String
                      .valueOf(record.id), record.db,
                      record.tableName, record.indexName,
                      record.fieldList, record.filterFieldList);
              session.write(cmd);
              cmd.await(3000, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
            } catch (Exception e) {
              log
                  .error(
                      "Open  index failure when connection was connected",
                      e);
            }
          }
        }
      } finally {
        HandlerSocketConnectorImpl.this.addSession(this.session);
      }

    }
  }

  /**
   * Session monitor for healing sessions.
   *
   * @author dennis
   *
   */
  class SessionMonitor extends Thread {
    public SessionMonitor() {
      this.setName("Heal-Session-Thread");
    }

    @Override
    public void run() {
      while (HandlerSocketConnectorImpl.this.isStarted()) {
          ReconnectRequest request=null;
          InetSocketAddress address=null;
        try {
           request = HandlerSocketConnectorImpl.this.waitingQueue
              .take();

           address = request.getRemoteAddr();

          boolean connected = false;
          Future<Boolean> future = HandlerSocketConnectorImpl.this
              .connect(request.getRemoteAddr());
          request.setTries(request.getTries() + 1);
          try {
            log.warn("Trying to connect to "
                + address.getAddress().getHostAddress() + ":"
                + address.getPort() + " for "
                + request.getTries() + " times");
            if (!future.get(HSClient.DEFAULT_CONNECT_TIMEOUT,
                TimeUnit.MILLISECONDS)) {
              connected = false;
            } else {
              connected = true;
              break;
            }
          } catch (TimeoutException e) {
            future.cancel(true);
          } catch (ExecutionException e) {
            future.cancel(true);
          } finally {
            if (!connected) {
              // update timestamp for next reconnecting
              rescheduleConnectRequest(request, address);
            } else {
              continue;
            }
          }

        } catch (InterruptedException e) {
          // ignore,check status
        } catch (Exception e) {
          log.error("SessionMonitor connect error", e);
          rescheduleConnectRequest(request, address);
        }
      }
    }

        private void rescheduleConnectRequest(ReconnectRequest request, InetSocketAddress address) {
            if(request==null)
                return;
            request
                .updateNextReconnectTimeStamp(HandlerSocketConnectorImpl.this.healSessionInterval
                    * request.getTries());
            log.error("Reconnect to "
                + address.getAddress().getHostAddress()
                + ":" + address.getPort() + " fail");
            // add to tail
            HandlerSocketConnectorImpl.this.waitingQueue
                .offer(request);
        }
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.google.code.hs4j.network.hs.HandlerCOnnector#setHealSessionInterval
   * (long)
   */
  public final void setHealSessionInterval(long healConnectionInterval) {
    this.healSessionInterval = healConnectionInterval;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.google.code.hs4j.network.hs.HandlerCOnnector#getHealSessionInterval()
   */
  public long getHealSessionInterval() {
    return this.healSessionInterval;
  }

  /*
   * (non-Javadoc)
   *
   * @see com.google.code.hs4j.network.hs.HandlerCOnnector#getProtocol()
   */
  public Protocol getProtocol() {
    return this.protocol;
  }

  protected final CopyOnWriteArrayList<Session> sessionList = new CopyOnWriteArrayList<Session>();

  /*
   * (non-Javadoc)
   *
   * @see
   * com.google.code.hs4j.network.hs.HandlerCOnnector#addSession(com.google
   * .code.hs4j.network.core.Session)
   */
  public void addSession(Session session) {
    InetSocketAddress remoteSocketAddress = session
        .getRemoteSocketAddress();
    log.warn("Add a session: "
        + SystemUtils.getRawAddress(remoteSocketAddress) + ":"
        + remoteSocketAddress.getPort());
    this.sessionList.add(session);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.google.code.hs4j.network.hs.HandlerCOnnector#removeSession(com.google
   * .code.hs4j.network.core.Session)
   */
  public void removeSession(Session session) {
    InetSocketAddress remoteSocketAddress = session
        .getRemoteSocketAddress();
    log.warn("Remove a session: "
        + SystemUtils.getRawAddress(remoteSocketAddress) + ":"
        + remoteSocketAddress.getPort());
    this.sessionList.remove(session);
  }

  @Override
  protected void doStart() throws IOException {
    this.setLocalSocketAddress(new InetSocketAddress("localhost", 0));
  }

  @Override
  public void onConnect(SelectionKey key) throws IOException {
    key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT);
    ConnectFuture future = (ConnectFuture) key.attachment();
    if (future == null || future.isCancelled()) {
        cancelKey(key);
      return;
    }
    try {
      if (!((SocketChannel) key.channel()).finishConnect()) {
        future.failure(new IOException("Connect to "
            + SystemUtils.getRawAddress(future.getRemoteAddr())
            + ":" + future.getRemoteAddr().getPort() + " fail"));
      } else {
        key.attach(null);
        this.createSession((SocketChannel) key.channel());
        future.setResult(Boolean.TRUE);
      }
    } catch (Exception e) {
      future.failure(e);
      cancelKey(key);
      throw new IOException("Connect to "
          + SystemUtils.getRawAddress(future.getRemoteAddr()) + ":"
          + future.getRemoteAddr().getPort() + " fail,"
          + e.getMessage());
    }
  }
 
   private void cancelKey(SelectionKey key) throws IOException {
       try {
           if (key.channel() != null)
               key.channel().close();
         
       finally {
           key.cancel();
       }
   }

  protected HandlerSocketSessionImpl createSession(SocketChannel socketChannel) {
    final HandlerSocketSessionImpl session = (HandlerSocketSessionImpl) this
        .buildSession(socketChannel);
    this.selectorManager.registerSession(session, EventType.ENABLE_READ);
    session.start();
    session.onEvent(EventType.CONNECTED, null);
    this.hsClient.notifyConnected(session);
    this.openIndexExectur.execute(new AddSessionTask(session));
    return session;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.google.code.hs4j.network.hs.HandlerCOnnector#addToWatingQueue(com
   * .google.code.hs4j.impl.ReconnectRequest)
   */
  public void addToWatingQueue(ReconnectRequest request) {
    this.waitingQueue.add(request);
  }

  /*
   * (non-Javadoc)
   *
   * @seecom.google.code.hs4j.network.hs.HandlerCOnnector#connect(java.net.
   * InetSocketAddress)
   */
  public Future<Boolean> connect(InetSocketAddress remoteAddr)
      throws IOException {
    if (remoteAddr == null) {
      throw new NullPointerException("Null Address");
    }
    SocketChannel socketChannel = SocketChannel.open();
    this.configureSocketChannel(socketChannel);
    ConnectFuture future = new ConnectFuture(remoteAddr);
    try {
        if (!socketChannel.connect(remoteAddr)) {
            this.selectorManager.registerChannel(socketChannel,
                SelectionKey.OP_CONNECT, future);
        } else {
            this.createSession(socketChannel);
            future.setResult(true);
        }
        return future;
     }
    catch (IOException e) {
        if (socketChannel != null) {
            socketChannel.close();
        }
        throw e;
    }
  }

  public void closeChannel(Selector selector) throws IOException {
    // do nothing
  }

  private final AtomicInteger sets = new AtomicInteger();

  public Session selectSession() throws HandlerSocketException {
    Session session = this.sessionList.get(this.sets.incrementAndGet()
        % this.sessionList.size());
    int retryCount = 0;
    while ((session == null || session.isClosed()) && retryCount++ < 6) {
      session = this.sessionList.get(this.sets.incrementAndGet()
          % this.sessionList.size());
    }
    if (session == null || session.isClosed()) {
      throw new HandlerSocketException(
          "Could not find an open connection");
    }
    return session;
  }

  /*
   * (non-Javadoc)
   *
   * @see com.google.code.hs4j.network.hs.HandlerCOnnector#getSessionList()
   */
  public CopyOnWriteArrayList<Session> getSessionList() {
    return this.sessionList;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.google.code.hs4j.network.hs.HandlerCOnnector#send(com.google.code
   * .hs4j.Command)
   */
  public void send(final Command msg) throws HandlerSocketException {
    Session session = this.selectSession();
    session.write(msg);
  }

  /**
   * Inner state listenner,manage session monitor.
   *
   * @author boyan
   *
   */
  class InnerControllerStateListener implements ControllerStateListener {
    private final SessionMonitor sessionMonitor = new SessionMonitor();

    public void onAllSessionClosed(Controller controller) {

    }

    public void onException(Controller controller, Throwable t) {
      log.error("Exception occured in controller", t);
    }

    public void onReady(Controller controller) {
      this.sessionMonitor.start();
    }

    public void onStarted(Controller controller) {

    }

    public void onStopped(Controller controller) {
      this.sessionMonitor.interrupt();
      HandlerSocketConnectorImpl.this.openIndexExectur.shutdown();
    }

  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.google.code.hs4j.network.hs.HandlerCOnnector#isAllowAutoReconnect()
   */
  public boolean isAllowAutoReconnect() {
    return this.allowAutoReconnect;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.google.code.hs4j.network.hs.HandlerCOnnector#setAllowAutoReconnect
   * (boolean)
   */
  public void setAllowAutoReconnect(boolean allowAutoReconnect) {
    this.allowAutoReconnect = allowAutoReconnect;
  }

  public HandlerSocketConnectorImpl(Configuration configuration,
      CommandFactory commandFactory, int poolSize, HSClientImpl hsClient) {
    super(configuration, null);
    this.protocol = commandFactory.getProtocol();
    this.addStateListener(new InnerControllerStateListener());
    this.connectionPoolSize = poolSize;
    this.soLingerOn = true;
    this.commandFactory = commandFactory;
    this.hsClient = hsClient;
    this
        .setSelectorPoolSize(2 * Runtime.getRuntime()
            .availableProcessors());
  }

  @Override
  protected NioSession buildSession(SocketChannel sc) {
    Queue<WriteMessage> queue = this.buildQueue();
    final NioSessionConfig sessionCofig = this
        .buildSessionConfig(sc, queue);
    HandlerSocketSessionImpl session = new HandlerSocketSessionImpl(
        sessionCofig, this.configuration.getSessionReadBufferSize(),
        this.getReadThreadCount(), this.commandFactory);
    session.setAllowReconnect(this.allowAutoReconnect);
    return session;
  }

}
TOP

Related Classes of com.google.code.hs4j.network.hs.HandlerSocketConnectorImpl$InnerControllerStateListener

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.