All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.piax.gtrans.handover.HandoverTransport Maven / Gradle / Ivy

The newest version!
/*
 * HandoverTransport.java
 * 
 * Copyright (c) 2012-2015 National Institute of Information and 
 * Communications Technology
 * 
 * You can redistribute it and/or modify it under either the terms of
 * the AGPLv3 or PIAX binary code license. See the file COPYING
 * included in the PIAX package for more in detail.
 * 
 * $Id: HandoverTransport.java 1176 2015-05-23 05:56:40Z teranisi $
 */

package org.piax.gtrans.handover;

import java.io.IOException;
import java.util.List;

import org.piax.common.Endpoint;
import org.piax.common.PeerId;
import org.piax.common.PeerIdWithLocator;
import org.piax.common.TransportId;
import org.piax.gtrans.ChannelTransport;
import org.piax.gtrans.IdConflictException;
import org.piax.gtrans.NoSuchPeerException;
import org.piax.gtrans.Peer;
import org.piax.gtrans.PeerLocator;
import org.piax.gtrans.ProtocolUnsupportedException;
import org.piax.gtrans.ReceivedMessage;
import org.piax.gtrans.Transport;
import org.piax.gtrans.impl.BaseTransportMgr;
import org.piax.gtrans.impl.DatagramBasedTransport;
import org.piax.gtrans.impl.IdResolver;
import org.piax.gtrans.impl.LocatorStatusObserver;
import org.piax.gtrans.impl.NestedMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 */
public class HandoverTransport extends
        DatagramBasedTransport implements
        LocatorStatusObserver {
    /*
     * HandoverTransportは下位のtransportが定まらないため、DatagramBasedTransportを
     * 実装テンプレートとして用いている。
     * channelの実装を考えると、OneToOneMappingTransportを用いるのがよいが、下位のtransport
     * の変更とともに、下位のchannelまで変更されると、channelの維持が困難になるため。
     */
    
    /*--- logger ---*/
    private static final Logger logger = 
            LoggerFactory.getLogger(HandoverTransport.class);

    final Peer peer;
    final IdResolver idResolver;
    final BaseTransportMgr baseTransMgr;
    
    public HandoverTransport(Peer peer, TransportId transId)
            throws IdConflictException {
        super(peer, transId, null, true);
        this.peer = peer;
        idResolver = peer.getIdResolver();
        baseTransMgr = peer.getBaseTransportMgr();
    }

    @Override
    public synchronized void fin() {
        super.fin();
        broadcastPeerFin();
    }

    @Override
    public Transport getBaseTransport() {
        return baseTransMgr.getRecentlyUsedTransport();
    }

    public PeerId getEndpoint() {
        return peerId;
    }

    private PeerLocator selectLocator(PeerId target) {
        if (!idResolver.contains(target)) return null;
        List locs = idResolver.getLocators(target);
        for (PeerLocator loc : locs) {
            Transport bt = baseTransMgr.getApplicableBaseTransport(loc);
            if (bt != null) return loc;
        }
        return null;
    }
    
    @Override
    protected void lowerSend(PeerId dst, NestedMessage nmsg)
            throws ProtocolUnsupportedException, IOException {
        Transport bt;
        PeerId peerId = null;
        PeerLocator loc = null;
//        if (dst instanceof PeerLocator) {
//            // このケースは例外にしてもよいかもしれない
//            logger.info("destination is not PeerId");
//            loc = (PeerLocator) dst;
//            bt = baseTransMgr.getApplicableBaseTransport(loc);
//        }
//        else 
        if (dst instanceof PeerIdWithLocator) {
            peerId = ((PeerIdWithLocator) dst).getPeerId();
            loc = ((PeerIdWithLocator) dst).getLocator();
            bt = baseTransMgr.getApplicableBaseTransport(loc);
        }
        else if (dst instanceof PeerId) {
            peerId = (PeerId) dst;
            loc = selectLocator(peerId);
            if (loc == null) {
                throw new NoSuchPeerException(
                        "No such PeerLocator could send to " + dst);
            }
            bt = baseTransMgr.getApplicableBaseTransport(loc);
        } else {
            bt = null;
        }
        if (bt == null) {
            throw new ProtocolUnsupportedException(
                    "No such Transport could send to " + dst);
        }
        bt.send(transId, loc, nmsg);
        
        /*
         * idResolverにエントリがなく、peerが初めて通信する相手である場合に、
         * 自peerが持っているすべてのlocatorをそのpeerに通知する
         */
        if (peerId != null && !idResolver.contains(peerId)) {
            idResolver.set(peerId, loc);
            for (PeerLocator myLoc : baseTransMgr.getAvailableLocators()) {
                sendIdLocChange(bt, loc, myLoc, null);
            }
        }
    }

    @Override
    protected NestedMessage _preReceive(ReceivedMessage rmsg) {
        NestedMessage nmsg = (NestedMessage) rmsg.getMessage();
        // 来たアドレス情報をidResolverの表に追記する
        idResolver.add(nmsg.srcPeerId, (PeerLocator) rmsg.getSource());
        // idResolverの表の更新を行う(制御メッセージの処理)
        if (nmsg.getInner() == null && nmsg.option instanceof PeerLocator[]) {
            if (peerId.equals(nmsg.srcPeerId)) {
                logger.warn("locator change command from me has no effect");
            } else {
                PeerLocator[] changes = (PeerLocator[]) nmsg.option;
                PeerLocator addLoc = changes[0];
                PeerLocator removeLoc = changes[1];
                if (addLoc == null && removeLoc == null) {
                    idResolver.removeAll(nmsg.srcPeerId);
                } else {
                    if (addLoc != null) {
                        idResolver.add(nmsg.srcPeerId, addLoc);
                    }
                    if (removeLoc != null) {
                        idResolver.remove(nmsg.srcPeerId, removeLoc);
                    }
                }
            }
            // 続きのonReceiveの処理を行わせないため、nullを返す
            return null;
        }
        return nmsg;
    }

    private  void sendIdLocChange(Transport bt, E target, 
            PeerLocator addLoc, PeerLocator removeLoc)
                    throws ProtocolUnsupportedException, IOException {
        // TODO changeコマンドは簡易実装になっている
        PeerLocator[] changes = new PeerLocator[] {addLoc, removeLoc};
        NestedMessage nmsg = new NestedMessage(null, null, peerId, 
                bt.getEndpoint(), 0, changes, null);
        bt.send(transId, target, nmsg);
    }
    
    private  void sendIdLocChange(E target, PeerLocator addLoc,
            PeerLocator removeLoc) throws ProtocolUnsupportedException,
            IOException {
        Transport bt = baseTransMgr.getApplicableBaseTransport(target);
        if (bt == null) {
            throw new ProtocolUnsupportedException(
                    "No such Transport could send to " + target);
        }
        sendIdLocChange(bt, target, addLoc, removeLoc);
    }
    
    private void broadcastIdLocChange(PeerLocator addLoc, PeerLocator removeLoc) {
        List peers = idResolver.getPeerIds();
        for (PeerId peer : peers) {
            PeerLocator loc = selectLocator(peer);
            try {
                if (loc == null) {
                    throw new NoSuchPeerException(
                            "No such PeerLocator could send to " + peer);
                }
                sendIdLocChange(loc, addLoc, removeLoc);
            } catch (IOException e) {
                logger.warn("", e);
            }
        }
    }

    private void broadcastLocatorChange(PeerLocator addLoc, PeerLocator removeLoc) {
        broadcastIdLocChange(addLoc, removeLoc);
    }
    
    private void broadcastPeerFin() {
        // TODO think!
        broadcastIdLocChange(null, null);
    }

    @Override
    public synchronized void onEnabled(Endpoint loc, boolean isNew) {
        try {
            Transport bt = baseTransMgr.newBaseTransport(null,
                    null, (PeerLocator)loc);
            bt.setListener(transId, this);
            if (bt instanceof ChannelTransport) {
                ((ChannelTransport) bt).setChannelListener(
                        transId, this);
            }
            broadcastLocatorChange((PeerLocator)loc, null);
        } catch (IOException e) {
            logger.warn("", e);
        } catch (IdConflictException e) {
            logger.error("", e);
        }
    }

    @Override
    public synchronized void onFadeout(Endpoint loc, boolean isFin) {
        Transport bt = baseTransMgr.removeBaseTransport((PeerLocator)loc);
        if (bt != null) {
            // btはfinしているので、listenerを削除する必要はない
//            bt.setListener(transId, null);
//            bt.setChannelListener(transId, null);
            broadcastLocatorChange(null, (PeerLocator)loc);
        }
    }

    @Override
    public synchronized void onChanging(PeerLocator oldLoc, PeerLocator newLoc) {
        Transport oldBt = baseTransMgr.removeBaseTransport(oldLoc);
        if (oldBt == null) {
            onEnabled(newLoc, false);
            return;
        }
        try {
            Transport newBt = baseTransMgr.newBaseTransport(
                    null, null, newLoc);
            newBt.setListener(transId, this);
            if (newBt instanceof ChannelTransport) {
                ((ChannelTransport) newBt).setChannelListener(
                        transId, this);
            }
            broadcastLocatorChange(newLoc, oldLoc);
            return;
        } catch (IOException e) {
            logger.warn("", e);
        } catch (IdConflictException e) {
            logger.error("", e);
        }
        broadcastLocatorChange(null, oldLoc);
    }

    @Override
    public void onHangup(PeerLocator loc, Exception cause) {
        // TODO causeの処理をしていない
        onFadeout(loc, false);
    }

    @Override
    protected boolean useReceiverThread(int numProc) {
        return false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy