org.piax.gtrans.impl.OneToOneMappingTransport Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of piax-compat Show documentation
Show all versions of piax-compat Show documentation
A backward compatibility package for PIAX
The newest version!
/*
* OneToOneMappingTransport.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: OneToOneMappingTransport.java 718 2013-07-07 23:49:08Z yos $
*/
package org.piax.gtrans.impl;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.piax.common.Endpoint;
import org.piax.common.ObjectId;
import org.piax.common.PeerId;
import org.piax.common.TransportId;
import org.piax.gtrans.Channel;
import org.piax.gtrans.ChannelListener;
import org.piax.gtrans.ChannelTransport;
import org.piax.gtrans.IdConflictException;
import org.piax.gtrans.ProtocolUnsupportedException;
import org.piax.gtrans.ReceivedMessage;
import org.piax.gtrans.TransOptions;
import org.piax.gtrans.Transport;
import org.piax.gtrans.TransportListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 下位層にTransportを持ち、send, channel.send をそのまま下位層のTransportに流すような
* Transportを作成するためのテンプレートクラス
*
*
*/
public abstract class OneToOneMappingTransport extends
ChannelTransportImpl implements TransportListener,
ChannelListener {
/*--- logger ---*/
private static final Logger logger = LoggerFactory
.getLogger(OneToOneMappingTransport.class);
/**
* OneToOneMappingTransportの内部で使用する下位層のchannelをラップするだけの
* ChannelImplクラス
*/
protected static class OneToOneChannel extends ChannelImpl {
final Channel lowerCh;
// new client channel
OneToOneChannel(Channel lowerCh, ChannelTransport mother,
ObjectId localObjId, ObjectId remoteObjId, E remote) {
super(mother, localObjId, remoteObjId, remote, true);
this.lowerCh = lowerCh;
}
// new accepted channel
OneToOneChannel(Channel lowerCh, PeerId creator,
ChannelTransport mother, ObjectId localObjId,
ObjectId remoteObjId, E remote) {
super(creator, mother, localObjId, remoteObjId, remote, true);
this.lowerCh = lowerCh;
}
@Override
public void close() {
/* onReceiveの処理途中でclose処理が入ると、accept channelと間違うなど
* おかしな動作をするので、lowerChで排他処理を行う。
* XXX これは十分ではない?
*/
synchronized (lowerCh) {
super.close();
((OneToOneMappingTransport) mother).removeCh(lowerCh);
lowerCh.close();
}
}
@Override
public void send(Object msg) throws IOException {
((OneToOneMappingTransport) mother).chSend(this, msg);
}
};
/** 下位層のchannelからOneToOneChannelを引くためのmap */
private final Map, OneToOneChannel> relatedChMap =
new HashMap, OneToOneChannel>();
protected OneToOneMappingTransport(TransportId transId,
ChannelTransport lowerTrans) throws IdConflictException {
super(lowerTrans.getPeer(), transId, lowerTrans, lowerTrans.supportsDuplex());
lowerTrans.setListener(transId, this);
lowerTrans.setChannelListener(transId, this);
}
@Override
public E getEndpoint() {
return getLowerTransport().getEndpoint();
}
@Override
public int getMTU() {
return lowerTrans.getMTU();
}
/*
* 下位層にセットするlowerTransは、ChannelTransportでかつ、
* destination が E と一致することに注意
*/
@Override
public ChannelTransport getLowerTransport() {
@SuppressWarnings("unchecked")
ChannelTransport lower = (ChannelTransport) lowerTrans;
return lower;
}
@Override
public Channel newChannel(ObjectId sender, ObjectId receiver, E dst,
boolean isDuplex, int timeout) throws ProtocolUnsupportedException,
IOException {
Channel lowerCh = getLowerTransport().newChannel(transId, dst,
isDuplex, timeout);
OneToOneChannel ch = new OneToOneChannel(lowerCh, this, sender,
receiver, dst);
if (lowerCh instanceof ChannelImpl) {
ch.setChannelNo(lowerCh.getChannelNo());
}
putCh(lowerCh, ch);
return ch;
}
protected OneToOneChannel putCh(Channel lowerCh, OneToOneChannel ch) {
synchronized (relatedChMap) {
return relatedChMap.put(lowerCh, ch);
}
}
protected void removeCh(Channel lowerCh) {
synchronized (relatedChMap) {
relatedChMap.remove(lowerCh);
}
}
protected OneToOneChannel getCh(Channel lowerCh) {
synchronized (relatedChMap) {
return relatedChMap.get(lowerCh);
}
}
public boolean onAccepting(Channel lowerCh) {
// log出力の便宜のため、currentThread名にpeerIdを付与する
peer.concatPeerId2ThreadName();
if (!this.isActive) {
logger.info("receive event purged");
return false;
}
return true;
}
public void onClosed(Channel lowerCh) {
// log出力の便宜のため、currentThread名にpeerIdを付与する
peer.concatPeerId2ThreadName();
if (!this.isActive) {
logger.info("receive event purged");
return;
}
ChannelImpl ch = getCh(lowerCh);
if (ch == null) {
// 制御用等に使われているlowerChは当該channelとの紐付けがないため、無視される
return;
}
ch.close();
// ** raise notification
// このTransportが作成したchannelについては無視する
if (!ch.remoteObjectId.equals(transId)) {
ChannelListener listener = getChannelListener(ch.localObjectId);
if (listener != null)
listener.onClosed(ch);
}
}
public void onFailure(Channel lowerCh, Exception cause) {
// log出力の便宜のため、currentThread名にpeerIdを付与する
peer.concatPeerId2ThreadName();
if (!this.isActive) {
logger.info("receive event purged");
return;
}
ChannelImpl ch = getCh(lowerCh);
if (ch == null) {
// 制御用等に使われているlowerChは当該channelとの紐付けがないため、無視される
return;
}
// ** raise notification
// このTransportが作成したchannelについては無視する
if (!ch.remoteObjectId.equals(transId)) {
ChannelListener listener = getChannelListener(ch.localObjectId);
if (listener != null)
listener.onFailure(ch, cause);
}
}
// *** about message sending ***
/*
* サブクラスで送信時のロジックを埋めるための用いる。
* 返り値には変換後のmsgを返す。
* nullを返すと処理を中断する
*/
protected Object _preSend(ObjectId sender, ObjectId receiver,
E dst, Object msg) throws IOException {
return msg;
};
protected void lowerSend(ObjectId sender, ObjectId receiver,
E dst, NestedMessage nmsg, TransOptions opts) throws ProtocolUnsupportedException,
IOException {
@SuppressWarnings("unchecked")
ChannelTransport lower = (ChannelTransport) lowerTrans;
lower.send(sender, receiver, dst, nmsg, opts);
}
protected void lowerChSend(Channel ch, NestedMessage nmsg) throws IOException {
ch.send(nmsg);
}
@Override
public void send(ObjectId sender, ObjectId receiver, E dst, Object msg, TransOptions opts)
throws ProtocolUnsupportedException, IOException {
logger.trace("ENTRY:");
// サブクラスで定義する送信前処理
Object _msg = _preSend(sender, receiver, dst, msg);
// _msgがnullの場合は処理を中断
if (_msg == null) return;
// msgをネストさせる
NestedMessage nmsg = new NestedMessage(sender, receiver, null,
getEndpoint(), _msg);
// 下位層のsendを呼ぶ
lowerSend(transId, transId, dst, nmsg, opts);
}
protected void chSend(OneToOneChannel ch, Object msg)
throws IOException {
logger.trace("ENTRY:");
// サブクラスで定義する送信前処理
Object _msg = _preSend(ch.localObjectId, ch.remoteObjectId, ch.remote, msg);
// _msgがnullの場合は処理を中断
if (_msg == null) return;
// msgをネストさせる
NestedMessage nmsg = new NestedMessage(ch.localObjectId,
ch.remoteObjectId, getPeerId(), getEndpoint(), _msg);
// 下位層のchannel.sendを呼ぶ
lowerChSend(ch.lowerCh, nmsg);
}
// *** about message receiving ***
/*
* サブクラスで受信時のロジックを埋めるための用いる。
* 返り値には変換後のmsgを返す。
* nullを返すと処理を中断する
*/
protected Object _postReceive(ObjectId sender, ObjectId receiver,
E src, Object msg) {
return msg;
}
@SuppressWarnings("unchecked")
private OneToOneChannel newAcceptCh(Channel lowerCh, NestedMessage nmsg) {
OneToOneChannel ch = new OneToOneChannel(lowerCh, nmsg.srcPeerId, this,
nmsg.receiver, nmsg.sender, (E) nmsg.src);
ch.setChannelNo(lowerCh.getChannelNo());
if (putCh(lowerCh, ch) != null) {
logger.error("invaild lower channel accepted");
}
return ch;
}
public void onReceive(Channel lowerCh) {
// log出力の便宜のため、currentThread名にpeerIdを付与する
peer.concatPeerId2ThreadName();
if (!this.isActive) {
logger.info("receive msg purged");
return;
}
NestedMessage nmsg = null;
OneToOneChannel ch = null;
synchronized (lowerCh) {
/*
* lowerCh.receive()で受理したメッセージを、ch.putReceiveQueueへ渡す順序を
* 保存するため、synchronized にしている
*/
if (lowerCh.isClosed()) return; // 既にcloseされていたらなにもしない。
nmsg = (NestedMessage) lowerCh.receive();
if (nmsg == null) {
logger.error("null message received");
return;
}
ch = _putReceiveQueue(lowerCh, nmsg);
}
if (ch != null && nmsg != null) {
_onReceive(ch, nmsg);
}
}
// Put the received nested message on the corresponding channel queue.
// Returns true if successfully finished.
@SuppressWarnings("unchecked")
protected OneToOneChannel _putReceiveQueue(Channel lowerCh, NestedMessage nmsg) {
/*
* TODO think!
* この処理では、下位から受信したメッセージを一回lowerCh.receiveしてから、
* このTransportの持つChannelのBlockingQueueにputしている。
* この場合は、下位層のBlockingQueueを共有することが効率的であるが、要検討
*/
logger.trace("ENTRY:");
OneToOneChannel ch = getCh(lowerCh);
if (ch == null) {
// channel未登録であることから、accept channelの処理を行う
ch = newAcceptCh(lowerCh, nmsg);
// listenerにdispatchする
ChannelListener listener = getChannelListener(nmsg.receiver);
if (listener != null) {
if (!listener.onAccepting(ch)) {
// listenerにacceptを拒否された場合
removeCh(lowerCh);
/*
* TODO 単純にメッセージを破棄する。
* acceptの拒否を送信元に送る必要があるが、このためには、newChannel時に
* 制御メッセージを交換する必要があるため、ペンディングにしておく。
*/
return null;
}
}
}
if (lowerCh.isClosed()) return null;
// サブクラスで定義する受信後処理を呼ぶ
Object _msg = _postReceive(nmsg.sender, nmsg.receiver, (E) nmsg.src,
nmsg.getInner());
// _msgがnullの場合は処理を中断
if (_msg == null) return null;
// chにinner msgをputする
ch.putReceiveQueue(_msg);
return ch;
}
protected void _onReceive(Channel ch, NestedMessage nmsg) {
if (ch != null) {
// listenerにdispatchする
ChannelListener listener = getChannelListener(nmsg.receiver);
if (listener != null) {
listener.onReceive(ch);
}
}
}
public void onReceive(Transport lowerTrans, ReceivedMessage rmsg) {
// log出力の便宜のため、currentThread名にpeerIdを付与する
peer.concatPeerId2ThreadName();
if (!this.isActive) {
logger.info("received msg purged {}", rmsg);
return;
}
NestedMessage nmsg = (NestedMessage) rmsg.getMessage();
_onReceive(lowerTrans, nmsg);
}
@SuppressWarnings("unchecked")
protected void _onReceive(Transport lowerTrans, NestedMessage nmsg) {
logger.trace("ENTRY:");
// サブクラスで定義する受信後処理を呼ぶ
Object _msg = _postReceive(nmsg.sender, nmsg.receiver, (E) nmsg.src,
nmsg.getInner());
// _msgがnullの場合は処理を中断
if (_msg == null) return;
// listenerにdispatchする
TransportListener listener = getListener(nmsg.receiver);
if (listener != null) {
listener.onReceive(this, new ReceivedMessage(nmsg.sender,
nmsg.src, _msg));
}
}
}