/**
* @copyright 2013 Computer Science Department, Recursive InterNetworking Architecture (RINA) laboratory, Boston University.
* All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation
* for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all
* copies and that both the copyright notice and this permission notice appear in supporting documentation.
* The RINA laboratory of the Computer Science Department at Boston University makes no
* representations about the suitability of this software for any purpose.
*/
package rina.ribDaemon.util;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import application.component.api.IPCResourceManager;
import com.google.protobuf.ByteString;
import rina.irm.impl.IRMImpl;
import rina.message.CDAP;
import rina.object.gpb.LinkStateRoutingEntrySet_t.routingEntrySetForwardedByNeighbor_t;
import rina.object.gpb.LinkStateRoutingEntrySet_t.routingEntrySet_t;
import rina.object.gpb.SubscriptionEvent_t.subscriptionEvent_t;
import rina.object.internal.ForwardingTable;
import rina.object.internal.Neighbor;
import rina.object.internal.Neighbors;
import rina.object.internal.SubscriptionEvent;
import rina.rib.impl.RIBImpl;
import rina.routing.util.LinkStateRoutingInfo;
/**
* For now each publisher publishes only one attributes
* Later we can optimized this
* @author Yuefeng Wang. Computer Science Department, Boston University
*
*/
public class Publisher extends Thread{
private Log log = LogFactory.getLog(this.getClass());
private RIBImpl rib = null;
private IPCResourceManager irm = null;
private String attribute = null;
private LinkedList<String> subscriberList = null; // remember for IPC process, this is an Integer
private double updatePeriod;
private SubscriptionEvent event = null;
private String IPCName = null;
private String IPCInstance = null;
private ForwardingTable forwardingTable = null;
private LinkStateRoutingInfo linkStateRoutingInfo = null;
private Neighbors neighbors = null;
private int rinaAddr = -1;
private boolean stop = false;
public Publisher(RIBImpl rib, IPCResourceManager irm,SubscriptionEvent event)
{
this.rib = rib;
this.irm = irm;
this.event = event;
this.attribute = this.event.getAtrributeList().get(0);
this.updatePeriod = this.event.getUpdatePeriod();
this.subscriberList = this.event.getMemberList();
this.IPCName = (String) this.rib.getAttribute("ipcName");
this.IPCInstance = (String)this.rib.getAttribute("ipcInstance");
this.neighbors = (Neighbors)this.rib.getAttribute("neighbors");
this.forwardingTable = (ForwardingTable) this.rib.getAttribute("forwardingTable");
this.linkStateRoutingInfo = (LinkStateRoutingInfo) this.rib.getAttribute("linkStateRoutingInfo");
this.rinaAddr = (Integer) this.rib.getAttribute("rinaAddr");
this.start();
}
public void run()
{
this.log.info("Publiser started with event id " + this.event.getSubscriptionID());
String rinaAddrString = Integer.toString(this.rinaAddr);
long sleepTime = Math.round(this.updatePeriod * 1000);
// this.log.debug("sleepTime in the publisher is " + sleepTime);
//int counter = 0;
while(!stop)
{
//update every one in the subscriberList some time
// it contains the publisher content in its value field
//this will be encapusluated in the CDAP M_CREATE objvalue
// counter++;
// this.log.debug("Publisher publishes for the " + counter + " times with frequency " + this.updatePeriod + ", for content "
// + this.attribute );
this.updatePubValue();
subscriptionEvent_t event_pub = this.event.getSendToSubscribers(rinaAddrString);
if(event_pub == null)
{
this.log.error("Publisher stopped due to empty content.");
this.stopPub();
continue;
}
CDAP.objVal_t.Builder obj = CDAP.objVal_t.newBuilder();
obj.setByteval(ByteString.copyFrom(event_pub.toByteArray()));
CDAP.CDAPMessage M_CREATE = rina.message.CDAPMessageGenerator.generateM_CREATE
( "subscription",
"/daf/subscription",
obj.buildPartial(),
99
);
// this.log.debug(" this.subscriberList.size():" + this.subscriberList.size());
for(int i = 0; i < this.subscriberList.size(); i++)
{
// NOTE: cast the subscriber type to int, as in IPC addr is an integer type not String
int subscriberAddr = Integer.parseInt( this.subscriberList.get(i) ) ;
// this.log.debug("ssssssssssssssssssssssssubscriberAddr is " + subscriberAddr);
int nextHop = this.forwardingTable.getNextHop(subscriberAddr);
if( nextHop == -1)
{
//TESTME
this.subscriberList.remove(Integer.toString(subscriberAddr));
this.log.info("Next hop does not exist for dstAddr " + subscriberAddr + ", thus remove it from the subscriberList" );
continue;
}
// this.log.debug("next hop of " + subscriberAddr + " is " + nextHop);
Neighbor neighbor = this.neighbors.getBeighbor(nextHop);
if(neighbor == null)
{
//TESTME
this.subscriberList.remove(Integer.toString(subscriberAddr));
this.log.info("Next hop does not exist for dstAddr " + subscriberAddr + ", thus remove it from the subscriberList" );
continue;
}
String dstIPCName = neighbor.getApName();
String dstIPCInstance = neighbor.getApInstance();
// this.log.debug( "Next hop IPC info:" + dstIPCName + "/" + dstIPCInstance );
int handleID = this.irm.allocateFlow(this.IPCName, this.IPCInstance, "Management", "1",
dstIPCName, dstIPCInstance, "Management", "1");
try {
this.irm.send(handleID, M_CREATE.toByteArray());
// this.log.info( " M_CREATE(subscription: pb) sent out over handleID " + handleID);
} catch (Exception e)
{
this.log.error(e.getMessage());
continue;
}
}
try {
Thread.sleep( sleepTime);
} catch (InterruptedException e) {
this.log.error(e.getMessage());
}
}
}
private void updatePubValue() {
byte[] value = null;
//Note: value may be set to null, if nothing exists
if(this.attribute.equals("linkStateRoutingEntry"))
{
routingEntrySet_t routingEntrySet = this.linkStateRoutingInfo.getRoutingEntrySet();
value = routingEntrySet.toByteArray();
}else if(this.attribute.equals("linkStateRoutingEntryNeighborsReceived"))
{
routingEntrySetForwardedByNeighbor_t routingEntrySetForwarded = this.linkStateRoutingInfo.getRoutingEntrySetForwardToNeighbor();
value = routingEntrySetForwarded.toByteArray();
}else if (this.attribute.equals("checkNeighborAlive"))
{
value = Long.toString(System.currentTimeMillis()).getBytes(); // send the current time out
}
this.event.setPubValue(value);
}
public synchronized void addSubsciber(String subscribeAddr)
{
if(!this.subscriberList.contains(subscribeAddr))
{
this.subscriberList.add(subscribeAddr);
}
}
public synchronized void removeSubsciber(String subscribeAddr)
{
this.subscriberList.remove(subscribeAddr);
}
/**
* Stop the publisher
*/
public void stopPub() {
this.stop = true;
}
}