/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs.backend.java.lib.net;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import abs.backend.java.lib.net.msg.COGMsg;
import abs.backend.java.lib.net.msg.CallMsg;
import abs.backend.java.lib.net.msg.Msg;
import abs.backend.java.lib.net.msg.ObjectMsg;
import abs.backend.java.lib.net.msg.ObjectTargetMsg;
import abs.backend.java.lib.net.msg.PromiseMsg;
import abs.backend.java.lib.runtime.ABSObject;
/**
* Representing a Node in the ABS network
*
* @author Jan Schäfer
*
*/
public class NodeImpl implements NetNode {
private final int id;
private final Router router;
private final Map<NetNode,ArcImpl> outArcs = new HashMap<NetNode, ArcImpl>();
private final List<ArcImpl> inArcs = new ArrayList<ArcImpl>();
private final Set<ABSObject> objects = new HashSet<ABSObject>();
private final Set<NetCOG> cogs = new HashSet<NetCOG>();
private final Random random = new Random();
public NodeImpl(int id) {
this.id = id;
router = new DefaultRouter(this);
}
public NodeImpl(int id, Router router) {
this.id = id;
this.router = router;
}
@Override
public void addInArcs(List<ArcImpl> arcs) {
inArcs.addAll(arcs);
}
@Override
public void addOutArcs(Map<NetNode, ArcImpl> arcs) {
outArcs.putAll(arcs);
}
public synchronized boolean processNextMsg() {
List<ArcImpl> shuffledList = new ArrayList<ArcImpl>(inArcs);
Collections.shuffle(shuffledList);
for (ArcImpl arc : shuffledList) {
if (!arc.getQueue().isEmpty()) {
Msg m = arc.getQueue().dequeue();
processMsg(m);
return true;
}
}
return false;
}
public void sendMsg(Msg m) {
}
@Override
public synchronized void processMsg(Msg m) {
if (m instanceof ObjectTargetMsg) {
ObjectTargetMsg otm = (ObjectTargetMsg) m;
if (objects.contains(otm.getTarget())) {
NetCOG cog = (NetCOG) otm.getTarget().getCOG();
cog.processMsg(m);
} else {
routeAway(m);
}
} else if (m instanceof COGMsg) {
COGMsg cm = (COGMsg) m;
NetCOG cog = cm.getCOG();
cog.setNode(this);
cogs.add(cog);
} else if (m instanceof ObjectMsg) {
ObjectMsg om = (ObjectMsg) m;
ABSObject object = om.getObject();
NetCOG cog = (NetCOG) object.getCOG();
if (cogs.contains(cog)) {
objects.add(object);
} else {
routeAway(m);
}
}
}
private void routeAway(Msg m) {
outArcs.get(getNextNode(m)).getQueue().enqueue(m);
}
private NetNode getNextNode(Msg m) {
NetNode node = router.getNextNode(m);
if (node == null) {
node = defaultRoute();
}
return node;
}
@Override
public NetNode defaultRoute() {
return null;
}
@Override
public void performStep() {
if (processNextMsg())
return;
if (migrateGroup())
return;
if (migrateObject())
return;
}
@Override
public synchronized void registerObject(ABSObject absObject) {
objects.add(absObject);
}
@Override
public synchronized void registerCOG(NetCOG cog) {
cogs.add(cog);
}
@Override
public Set<ABSObject> getRegisteredObjects() {
return objects;
}
@Override
public Set<NetCOG> getRegisteredCOGs() {
return cogs;
}
@Override
public int getId() {
return id;
}
private synchronized boolean migrateObject() {
for (ABSObject o : objects) {
NetCOG cog = (NetCOG)o.getCOG();
if (!cogs.contains(cog)) {
NetNode node = router.getRouteEntry(cog).getNextNode();
objects.remove(o);
outArcs.get(node).getQueue().enqueue(new ObjectMsg(o));
return true;
}
}
return false;
}
private synchronized boolean migrateGroup() {
if (random.nextBoolean())
return false;
if (cogs.isEmpty())
return false;
NetCOG cog = cogs.iterator().next();
cogs.remove(cog);
ArcImpl arc = outArcs.values().iterator().next();
arc.getQueue().enqueue(new COGMsg(cog));
return true;
}
}