fungus.HyphaLink.java Source code

Java tutorial

Introduction

Here is the source code for fungus.HyphaLink.java

Source

/* Copyright (c) 2014, Paul L. Snyder <paul@pataprogramming.com>,
 * Daniel Dubois, Nicolo Calcavecchia.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * Any later version. It may also be redistributed and/or modified under the
 * terms of the BSD 3-Clause License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package fungus;

import peersim.cdsim.*;
import peersim.config.*;
import peersim.core.*;
import java.util.*;
import java.util.logging.*;
import edu.uci.ics.jung.graph.*;
import edu.uci.ics.jung.graph.util.*;

import org.apache.commons.collections15.*;

public class HyphaLink implements Linkable, CDProtocol, Cleanable {

    private static final String PAR_HYPHADATA_PROTO = "network.node.hyphadata_proto";
    private static final String PAR_HYPHALINK_PROTO = "network.node.hyphalink_proto";
    private static final String PAR_MYCOCAST_PROTO = "network.node.mycocast_proto";

    private static int hyphaDataPid;
    private static int hyphaLinkPid;
    private static int mycoCastPid;

    private static Logger log = Logger.getLogger(HyphaLink.class.getName());

    //    private HyphaData data;
    //    private HyphaLink link;
    private MycoList neighbors;
    private MycoNode myNode;

    private static List<HyphaLinkListener> listeners = new ArrayList<HyphaLinkListener>();
    private static List<FailureAnnouncementListener> failureListeners = new ArrayList<FailureAnnouncementListener>();

    public HyphaLink(String prefix) {
        mycoCastPid = Configuration.getPid(PAR_MYCOCAST_PROTO);
        hyphaDataPid = Configuration.getPid(PAR_HYPHADATA_PROTO);
        hyphaLinkPid = Configuration.getPid(PAR_HYPHALINK_PROTO);

        myNode = null;
        // FIXME: May not work correctly with default clone()
        neighbors = new MycoList();
    }

    public void nextCycle(Node node, int pid) {
        myNode = (MycoNode) node;
        for (MycoNode neighbor : neighbors.duplicate()) {
            if (!neighbor.isUp()) {
                pruneNeighbor(neighbor);
            }
        }
        // data = (HyphaData) node.getProtocol(hyphaDataPid);
        // link = (HyphaLink) node.getProtocol(hyphaLinkPid);
    }

    public String toString() {
        String ret = "<HyphaLink: " + " ";
        HyphaData d;

        for (MycoNode n : neighbors) {
            d = (HyphaData) n.getProtocol(hyphaDataPid);
            ret += n + " " + d.toString() + " ";
        }
        ret += ">";
        return ret;
    }

    public boolean hasCapacity(MycoNode n) {
        HyphaData d;
        d = (HyphaData) n.getProtocol(hyphaDataPid);
        return neighbors.size() < d.getMaxCapacity();
    }

    public boolean withinCapacity(MycoNode n, double multiplier) {
        return neighbors.size() < (n.getHyphaData().getMaxCapacity() * multiplier);
    }

    public boolean addNeighbor(Node neighbor) {
        return addNeighbor((MycoNode) neighbor);
    }

    public boolean addNeighbor(MycoNode neighbor) {
        if (myNode == neighbor || neighbors.contains(neighbor)) {
            // do nothing; no double-entries, no self-links
        } else {
            neighbors.add(neighbor);
            fireLinkAdded(neighbor);
        }
        HyphaLink neighborLink = ((HyphaLink) neighbor.getProtocol(hyphaLinkPid));
        neighborLink.linkBack(myNode);
        MessageObserver.topoActionMessages(2);
        return true;
    }

    public int neighborCount() {
        return neighbors.size();
    }

    public boolean linkBack(MycoNode neighbor) {
        if (myNode == neighbor || neighbors.contains(neighbor)) {
            return true;
        }
        boolean ret = neighbors.add(neighbor);
        if (ret) {
            fireLinkAdded(neighbor);
        }
        return ret;
    }

    public MycoList deadNeighbors() {
        return neighbors.getDead();
    }

    public boolean removeNeighbor(MycoNode neighbor) {
        log.finer("REMOVING CONNECTION WITH " + neighbor);
        neighbors.remove(neighbor);
        fireLinkRemoved(neighbor);
        HyphaLink neighborLink = ((HyphaLink) neighbor.getProtocol(hyphaLinkPid));
        neighborLink.pruneNeighbor(myNode);
        MessageObserver.topoActionMessages(2);
        return true;
    }

    public boolean pruneNeighbor(MycoNode neighbor) {
        boolean ret = neighbors.remove(neighbor);
        if (ret) {
            fireLinkRemoved(neighbor);
        }
        return ret;
    }

    public MycoList getNeighbors() {
        return neighbors.duplicate();
    }

    public MycoList getSameNeighbors() {
        HyphaData d = ((HyphaData) (myNode).getProtocol(hyphaDataPid));
        return neighbors.getType(d.getType());
    }

    public MycoList getDifferentNeighbors() {
        HyphaData d = ((HyphaData) (myNode).getProtocol(hyphaDataPid));
        return neighbors.getTypeNot(d.getType());
    }

    public MycoList getBiomass() {
        return neighbors.getBiomass();
    }

    public MycoList getHyphae() {
        return neighbors.getHyphae();
    }

    public MycoList getImmobile() {
        return neighbors.getImmobile();
    }

    public MycoList getBranching() {
        return neighbors.getBranching();
    }

    public MycoList getExtending() {
        return neighbors.getExtending();
    }

    public MycoList getStable() {
        return neighbors.getStable();
    }

    public boolean contains(Node neighbor) {
        return neighbors.contains(neighbor);
    }

    public boolean isDisconnected() {
        return neighbors.isEmpty();
    }

    public int idealHyphae() {
        HyphaData d = ((HyphaData) (myNode).getProtocol(hyphaDataPid));
        return d.getIdealHyphae();
    }

    public int idealOtherHyphae() {
        HyphaData d = ((HyphaData) (myNode).getProtocol(hyphaDataPid));
        return d.getIdealOtherHyphae();
    }

    public boolean isIdealHyphae() {
        return (hyphaDegree() == idealHyphae());
    }

    public boolean isOverHyphae() {
        return (hyphaDegree() > idealHyphae());
    }

    public boolean isUnderHyphae() {
        return (hyphaDegree() < idealHyphae());
    }

    public boolean isAtOrOverHyphae() {
        return (hyphaDegree() >= idealHyphae());
    }

    public int idealBiomass() {
        return myNode.getHyphaData().getIdealBiomass();
    }

    public boolean isIdealSameHyphae() {
        return (sameHyphaDegree() == idealHyphae());
    }

    public boolean isOverSameHyphae() {
        return (sameHyphaDegree() > idealHyphae());
    }

    public boolean isUnderSameHyphae() {
        return (sameHyphaDegree() < idealHyphae());
    }

    public boolean isAtOrOverSameHyphae() {
        return (sameHyphaDegree() >= idealHyphae());
    }

    public boolean isIdealDifferentHyphae() {
        return (differentHyphaDegree() == idealOtherHyphae());
    }

    public boolean isOverDifferentHyphae() {
        return (differentHyphaDegree() > idealOtherHyphae());
    }

    public boolean isAtOrOverDifferentHyphae() {
        return (differentHyphaDegree() >= idealOtherHyphae());
    }

    public boolean isUnderDifferentHyphae() {
        return (differentHyphaDegree() < idealOtherHyphae());
    }

    public boolean isOverBiomass() {
        return (sameBiomassDegree() > idealBiomass());
    }

    public boolean isUnderBiomass() {
        return (sameBiomassDegree() < idealBiomass());
    }

    public int amountOverBiomass() {
        return (sameBiomassDegree() - idealBiomass());
    }

    public int amountUnderBiomass() {
        return (idealBiomass() - sameBiomassDegree());
    }

    public int amountOverSameHyphae() {
        return (sameHyphaDegree() - idealHyphae());
    }

    public int amountUnderSameHyphae() {
        return (idealHyphae() - sameHyphaDegree());
    }

    public int degree() {
        return neighbors.size();
    }

    public int sameDegree() {
        return getSameNeighbors().size();
    }

    public int differentDegree() {
        return getDifferentNeighbors().size();
    }

    public int hyphaDegree() {
        return neighbors.getHyphae().size();
    }

    public int sameHyphaDegree() {
        return getSameNeighbors().getHyphae().size();
    }

    public int differentHyphaDegree() {
        return getDifferentNeighbors().getHyphae().size();
    }

    public int biomassDegree() {
        return neighbors.getBiomass().size();
    }

    public int sameBiomassDegree() {
        return getSameNeighbors().getBiomass().size();
    }

    public MycoNode getRandomNeighbor() {
        return neighbors.getRandom();
    }

    public MycoNode getRandomSameNeighbor() {
        return neighbors.getRandomOfType(myNode.getHyphaData().getType());
    }

    public MycoNode getRandomSameHypha() {
        return neighbors.getHyphae().getRandomOfType(myNode.getHyphaData().getType());
    }

    public MycoNode getNeighbor(int i) {
        return neighbors.get(i);
    }

    public int getNeighborhoodCapacity() {
        int cap = 0;
        for (MycoNode n : neighbors.getType(myNode.getHyphaData().getType())) {
            cap += n.getHyphaData().getCapacity();
        }
        return cap;
    }

    public int getNeighborhoodQueueLength() {
        int len = 0;
        for (MycoNode n : neighbors.getType(myNode.getHyphaData().getType())) {
            len += n.getHyphaData().getQueueLength();
        }
        return len;
    }

    // Return a list of all nodes two jumps away in the graph
    public MycoList get2Neighbors() {
        Set<MycoNode> set = new HashSet<MycoNode>();
        for (MycoNode n : getHyphae()) {
            set.addAll(n.getHyphaLink().getNeighbors());
        }
        set.remove(myNode);
        set.remove(neighbors);
        return new MycoList(set);
    }

    // Return a list of all nodes within two jump
    public MycoList get2Neighborhood() {
        Set<MycoNode> set = new HashSet<MycoNode>();
        for (MycoNode n : getHyphae()) {
            set.add(n);
            set.addAll(n.getHyphaLink().getNeighbors());
        }
        set.remove(myNode);
        return new MycoList(set);
    }

    // get the highest capacity biomass node from among all neighbors
    // (except those specified in exclude) (of same type)
    public MycoList getMaxNeighborBiomass(Collection<MycoNode> exclude) {
        MycoNode maxBiomass = null;
        int maxBiomassCapacity = 0;

        MycoNode t;
        MycoNode owningNeighbor = null;
        HyphaData d;
        for (MycoNode n : getSameNeighbors().getHyphae()) {
            if (exclude.contains(n)) {
                continue;
            }
            t = n.getHyphaLink().getMaxBiomass();
            if (t == null) {
                continue;
            }
            d = t.getHyphaData();
            if (d.getMaxCapacity() > maxBiomassCapacity) {
                maxBiomassCapacity = d.getMaxCapacity();
                maxBiomass = t;
                owningNeighbor = n;
            }
        }
        // Return max biomass node as the first list element,
        //  and the owning neighbor as the second
        MycoList ret = new MycoList();
        if (maxBiomass != null) {
            ret.add(maxBiomass);
            ret.add(owningNeighbor);
        }
        return ret;
    }

    // get the highest capacity child biomass node (of the same type)
    public MycoNode getMaxBiomass() {
        HyphaData d;
        MycoNode maxBiomass = null;
        int maxBiomassCapacity = 0;
        for (MycoNode n : getSameNeighbors().getBiomass()) {
            d = n.getHyphaData();
            if (d.isBiomass() && (d.getMaxCapacity() > maxBiomassCapacity)) {
                maxBiomassCapacity = d.getMaxCapacity();
                maxBiomass = n;
            }
        }
        return maxBiomass;
    }

    public void transferBiomass(MycoNode target, int quantity) {
        int transferred = 0;
        for (MycoNode bio : getBiomass()) {
            if (transferred >= quantity) {
                break;
            }
            transferNeighbor(bio, target);
            transferred++;
        }
        log.log(Level.FINE, myNode + " TRANSFERRED " + quantity + " BIOMASS " + " TO " + target, myNode);
    }

    public boolean areNeighbors(MycoNode a, MycoNode b) {
        HyphaLink al = a.getHyphaLink();
        return al.isNeighbor(b);
    }

    public boolean isNeighbor(MycoNode b) {
        return neighbors.contains(b);
    }

    public MycoNode getParent() {
        if (myNode.getHyphaData().isBiomass()) {
            log.log(Level.FINEST, myNode + " QUERIED FOR PARENT; IS BIOMASS", myNode);
            MycoList h = getHyphae();
            if (h.size() > 0) {
                if (h.size() > 1) {
                    // FIXME: Handle multiple parents better!!!
                    log.log(Level.FINE, myNode + " MULTIPLE HYPHAE FOR BIOMASS NODE!", myNode);
                }
                return h.get(0);
            }
        }
        return null;
    }

    public void transferNeighbor(MycoNode neighbor, MycoNode target) {
        if (neighbor != null && target != null) {
            if (neighbor == target) {
                log.log(Level.FINER, myNode + " TRIED TO TRANSFER " + neighbor + " TO ITSELF.",
                        new Object[] { myNode, neighbor });
                return;
            }
            neighbors.remove(neighbor);
            fireLinkRemoved(neighbor);
            HyphaLink neighborLink = ((HyphaLink) neighbor.getProtocol(hyphaLinkPid));
            neighborLink.pruneNeighbor(myNode);

            if (areNeighbors(neighbor, target)) {
                log.log(Level.FINER, myNode + " TRIED TO TRANSFER " + target + " TO " + neighbor
                        + " BUT ARE ALREADY " + "CONNECTED", new Object[] { myNode, neighbor, target });
                return;
            }
            log.log(Level.FINER, myNode + " TRANSFERS " + neighbor + " TO " + target,
                    new Object[] { myNode, neighbor, target });
            HyphaLink targetLink = target.getHyphaLink();
            targetLink.addNeighbor(neighbor);
        } else {
            log.log(Level.WARNING, "BAD TRANSFER attempted from " + myNode + " TO " + target,
                    new Object[] { myNode, neighbor, target });
            (new Throwable()).printStackTrace();
            //FIXME: Warning
        }
    }

    public void absorbHypha(MycoNode target) {

        HyphaData myData = (HyphaData) myNode.getProtocol(hyphaDataPid);
        HyphaLink tl = (HyphaLink) target.getProtocol(hyphaLinkPid);
        HyphaData targetData = (HyphaData) target.getProtocol(hyphaDataPid);

        log.log(Level.FINER,
                myNode + " (" + myData.getState() + ") ABSORBS " + target + " (" + targetData.getState() + ")",
                new Object[] { myNode, target });

        if (targetData.isBiomass()) {
            log.log(Level.FINE, myNode.getID() + " TRIED TO ABSORB BIOMASS NODE " + target.getID(),
                    new Object[] { myNode, target });
            return;
        }

        // Move all target's hyphae to self
        MycoList hyphae = tl.getHyphae();
        for (MycoNode n : hyphae) {
            tl.transferNeighbor(n, myNode);
        }

        // Move all target's biomass to self
        MycoList biomass = tl.getBiomass();
        for (MycoNode n : biomass) {
            tl.transferNeighbor(n, myNode);
        }

        // Demote absorbed target to biomass
        targetData.becomeBiomass(target);
        //System.out.println("DEMOTED absorbed target " + target);
        //System.out.println("NEW NODE " + myNode);
    }

    public void swapHyphae(MycoNode target) {
        log.log(Level.FINE, myNode + " SWAPS WITH " + target, new Object[] { myNode, target });
        // Move all connected hyphae to target
        MycoList hyphae = this.getHyphae();
        for (MycoNode n : hyphae) {
            this.transferNeighbor(n, target);
        }

        // Move all connected biomass to target
        MycoList biomass = this.getBiomass();
        for (MycoNode n : biomass) {
            this.transferNeighbor(n, target);
        }

        // Promote target to same state as self

        HyphaData data = (HyphaData) (myNode.getProtocol(hyphaDataPid));
        HyphaData targetData = (HyphaData) target.getProtocol(hyphaDataPid);
        targetData.become(target, data.getState());

        // Demote self to biomass state
        data.becomeBiomass(myNode);
    }

    public MycoNode growHypha() {
        MycoNode newHypha = getMaxBiomass();
        if (newHypha != null) {
            log.log(Level.FINER, myNode + " GROWS HYPHA INTO " + newHypha, new Object[] { myNode, newHypha });
            HyphaData newHyphaData = (HyphaData) newHypha.getProtocol(hyphaDataPid);
            newHyphaData.becomeExtending(newHypha);
        }
        return newHypha;
    }

    public Object clone() {
        HyphaLink ret = null;
        try {
            ret = (HyphaLink) super.clone();
            ret.neighbors = new MycoList();
        } catch (CloneNotSupportedException e) {
            // Never happens
        }
        return ret;
    }

    @Override
    public void onKill() {
        if (myNode == null) {
            log.log(Level.FINER, "Cycle " + CDState.getCycle() + ": TRIED TO KILL UNINITIALIZED NODE");
            return;
        }
        HyphaData myData = (HyphaData) myNode.getProtocol(hyphaDataPid);
        log.log(Level.FINER, myNode + " (" + myData.getState() + ") HAS BEEN KILLED ", myNode);

        fireFailing(myNode, myData.getState(), degree(), myData.getParentTarget(), neighbors);
        MycoList removing = new MycoList(neighbors);
        for (MycoNode neighbor : removing) {
            HyphaLink nl = neighbor.getHyphaLink();
            nl.removeNeighbor(myNode);
        }
        neighbors.clear();

        /*
          List<Node> nl = new ArrayList<Node>(neighbors);
          for (Node neighbor : nl) {
          HyphaData nd = (HyphaData) neighbor.getProtocol(hyphaDataPid);
          log.finest(myNode.getID() + " SEVERING NEIGHBOR " +
          neighbor.getID() + " (" + nd.getState() + ")");
          removeNeighbor(neighbor);
          }
        */
    }

    public void pack() {
    }

    public static void addHyphaLinkListener(HyphaLinkListener l) {
        HyphaLink.listeners.add(l);
    }

    public static void removeHyphaLinkListener(HyphaLinkListener l) {
        HyphaLink.listeners.remove(l);
    }

    protected void fireLinkAdded(MycoNode neighbor) {
        if (myNode != null) {
            for (HyphaLinkListener l : HyphaLink.listeners) {
                l.linkAdded(myNode, neighbor);
            }
        }
    }

    protected void fireLinkRemoved(MycoNode neighbor) {
        if (myNode != null) {
            for (HyphaLinkListener l : HyphaLink.listeners) {
                l.linkRemoved(myNode, neighbor);
            }
        }
    }

    public static void addFailureListener(FailureAnnouncementListener l) {
        HyphaLink.failureListeners.add(l);
    }

    public static void removeFailureListener(FailureAnnouncementListener l) {
        HyphaLink.failureListeners.remove(l);
    }

    protected static void fireFailing(MycoNode n, HyphaType t, int degree, double parentTarget,
            MycoList neighbors) {
        for (FailureAnnouncementListener l : failureListeners) {
            l.notifyFailing(n, t, degree, parentTarget, neighbors);
        }
    }

    protected static void fireSevering(MycoNode n, HyphaType t, int degree, double parentTarget,
            MycoList neighbors) {
        for (FailureAnnouncementListener l : failureListeners) {
            l.notifySevering(n, t, degree, parentTarget, neighbors);
        }
    }

}