Package net.tomp2p.connection

Source Code of net.tomp2p.connection.PeerCreator

/*
* Copyright 2009 Thomas Bocek
*
* 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 net.tomp2p.connection;

import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

import java.io.IOException;
import java.net.InetAddress;
import java.security.KeyPair;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import net.tomp2p.futures.BaseFutureAdapter;
import net.tomp2p.futures.FutureDone;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerSocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Creates a peer and listens to incoming connections. The result of creating
* this class is the connection bean and the peer bean. While the connection
* bean holds information that can be shared, the peer bean holds information
* that is unique for each peer.
*
* @author Thomas Bocek
*
*/
public class PeerCreator {
  private static final Logger LOG = LoggerFactory.getLogger(PeerCreator.class);

  private final ConnectionBean connectionBean;
  private final PeerBean peerBean;

  private final List<PeerCreator> childConnections = new ArrayList<PeerCreator>();

  private final EventLoopGroup workerGroup;
  private final EventLoopGroup bossGroup;

  private final boolean master;

  private final FutureDone<Void> futureServerDone = new FutureDone<Void>();

  /**
   * Creates a master peer and starts UPD and TCP channels.
   *
   * @param p2pId
   *            The id of the network
   * @param peerId
   *            The id of this peer
   * @param keyPair
   *            The key pair or null
   * @param channelServerConfiguration
   *            The server configuration to create the channel server that is
   *            used for listening for incoming connections
   * @param channelClientConfiguration
   *            The client side configuration
   * @param timer
   *            The executor service
   * @param sendBehavior
   *         The sending behavior for direct messages
   * @throws IOException
   *             If the startup of listening to connections failed
   */
  public PeerCreator(final int p2pId, final Number160 peerId, final KeyPair keyPair,
          final ChannelServerConfiguration channelServerConfiguration,
          final ChannelClientConfiguration channelClientConfiguration,
          final ScheduledExecutorService timer, SendBehavior sendBehavior) throws IOException {
    //peer bean
    peerBean = new PeerBean(keyPair);
    PeerAddress self = findPeerAddress(peerId, channelClientConfiguration, channelServerConfiguration);
    peerBean.serverPeerAddress(self);
    LOG.info("Visible address to other peers: {}", self);
   
    //start server
    workerGroup = new NioEventLoopGroup(0, new DefaultThreadFactory(ConnectionBean.THREAD_NAME
            + "worker-client/server - "));
    bossGroup = new NioEventLoopGroup(2, new DefaultThreadFactory(ConnectionBean.THREAD_NAME + "boss - "));
    Dispatcher dispatcher = new Dispatcher(p2pId, peerBean, channelServerConfiguration.heartBeatMillis());
    final ChannelServer channelServer = new ChannelServer(bossGroup, workerGroup, channelServerConfiguration,
            dispatcher, peerBean.peerStatusListeners(), timer);
   
    //connection bean
    Sender sender = new Sender(peerId, peerBean.peerStatusListeners(), channelClientConfiguration, dispatcher, sendBehavior);
    Reservation reservation = new Reservation(workerGroup, channelClientConfiguration);
    connectionBean = new ConnectionBean(p2pId, dispatcher, sender, channelServer, reservation,
            channelClientConfiguration, timer);
    this.master = true;
  }

  /**
   * Creates a slave peer that will attach itself to a master peer.
   *
   * @param parent
   *            The parent peer
   * @param peerId
   *            The id of this peer
   * @param keyPair
   *            The key pair or null
   */
  public PeerCreator(final PeerCreator parent, final Number160 peerId, final KeyPair keyPair) {
    parent.childConnections.add(this);
    this.workerGroup = parent.workerGroup;
    this.bossGroup = parent.bossGroup;
    this.connectionBean = parent.connectionBean;
    this.peerBean = new PeerBean(keyPair);
    PeerAddress self = parent.peerBean().serverPeerAddress().changePeerId(peerId);
    this.peerBean.serverPeerAddress(self);
    this.master = false;
  }

  /**
   * Shutdown the peer. If the peer is a master, then also the connections and
   * the server will be closed, otherwise its just de-registering.
   *
   * @return The future when the shutdown is complete
   */
  public FutureDone<Void> shutdown() {
    if (master) {
      LOG.debug("shutdown in progress...");
    }
    // de-register in dispatcher
    connectionBean.dispatcher().removeIoHandler(peerBean().serverPeerAddress().peerId(), peerBean().serverPeerAddress().peerId());
    // shutdown running tasks for this peer
    if (peerBean.maintenanceTask() != null) {
      peerBean.maintenanceTask().shutdown();
    }
   
    // shutdown all children
    if (!master) {
      for (PeerCreator peerCreator : childConnections) {
        peerCreator.shutdown();
      }
      return shutdownFuture().done();
    }
    // shutdown the timer
    connectionBean.timer().shutdown();
   
    LOG.debug("starting shutdown done in client...");
    connectionBean.reservation().shutdown().addListener(new BaseFutureAdapter<FutureDone<Void>>() {
      @Override
      public void operationComplete(final FutureDone<Void> future) throws Exception {
        connectionBean.channelServer().shutdown().addListener(new BaseFutureAdapter<FutureDone<Void>>() {   
                    @Override
          public void operationComplete(final FutureDone<Void> future) throws Exception {
            shutdownNetty();
          }
        });
      }
    });
    // this is blocking
    return shutdownFuture();
  }
 
  @SuppressWarnings({ "unchecked", "rawtypes" })
    private void shutdownNetty() {
    workerGroup.shutdownGracefully(0, 0, TimeUnit.SECONDS).addListener(new GenericFutureListener() {
      @Override
      public void operationComplete(final Future future) throws Exception {
        LOG.debug("shutdown done in client / workerGroup...");
        bossGroup.shutdownGracefully(0, 0, TimeUnit.SECONDS).addListener(
                new GenericFutureListener() {
                  @Override
                  public void operationComplete(final Future future) throws Exception {
                    LOG.debug("shutdown done in client / bossGroup...");
                    shutdownFuture().done();
                  }
                });
      }
    });
  }

  /**
   * @return The shutdown future that is used when calling {@link #shutdown()}
   */
  public FutureDone<Void> shutdownFuture() {
    return futureServerDone;
  }

  /**
   * @return The bean that holds information that is unique for all peers
   */
  public PeerBean peerBean() {
    return peerBean;
  }

  /**
   * @return The bean that holds information that may be shared amoung peers
   */
  public ConnectionBean connectionBean() {
    return connectionBean;
  }

  /**
   * Creates the {@link PeerAddress} based on the network discovery that was
   * done in
   * {@link #ChannelServer(Bindings, int, int, ChannelServerConfiguration)}.
   *
   * @param peerId
   *            The id of this peer
   * @return The peer address of this peer
   * @throws IOException
   *             If the address could not be determined
   */
  private static PeerAddress findPeerAddress(final Number160 peerId,
          final ChannelClientConfiguration channelClientConfiguration,
          final ChannelServerConfiguration channelServerConfiguration) throws IOException {
    final DiscoverResults discoverResults = DiscoverNetworks.discoverInterfaces(
        channelClientConfiguration.bindings());
    final String status = discoverResults.status();
    if (LOG.isInfoEnabled()) {
      LOG.info("Status of external search: " + status);
    }
    //this is just a guess and will be changed once discovery is done
    InetAddress outsideAddress = discoverResults.foundAddress();
    if(outsideAddress == null) {
      throw new IOException("Not listening to anything. Maybe your binding information is wrong.");
    }
    final PeerSocketAddress peerSocketAddress = new PeerSocketAddress(outsideAddress, channelServerConfiguration.
        ports().tcpPort(), channelServerConfiguration.ports().udpPort());
    final PeerAddress self = new PeerAddress(peerId, peerSocketAddress,
            channelServerConfiguration.isBehindFirewall(), channelServerConfiguration.isBehindFirewall(), false, false, false,
            PeerAddress.EMPTY_PEER_SOCKET_ADDRESSES);
    return self;
  }
}
TOP

Related Classes of net.tomp2p.connection.PeerCreator

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.