package com.almende.eve.ggdemo; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.http.annotation.ThreadSafe; import com.almende.eve.protocol.jsonrpc.annotation.Access; import com.almende.eve.protocol.jsonrpc.annotation.AccessType; import com.almende.eve.protocol.jsonrpc.annotation.Name; import com.almende.eve.protocol.jsonrpc.annotation.Sender; import com.almende.eve.protocol.jsonrpc.formats.JSONRPCException; import com.almende.util.TypeUtil; import com.almende.util.URIUtil; import com.almende.util.jackson.JOM; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ObjectNode; @Access(AccessType.PUBLIC) @ThreadSafe public class HolonAgent extends AbstractLampAgent { private static final TypeUtil<ArrayList<Sub>> type = new TypeUtil<ArrayList<Sub>>() {}; public void create(@Name("neighbours") List<String> neighbors, @Name("stepSize") Integer stepSize) throws JSONRPCException, IOException { super.create(neighbors, stepSize); String taskId = schedule("checkMerge", null, (int) Math.random() * 1500); System.out.println(getId() + ": schedulertask created:" + taskId + " --> " + getScheduler()); } public void checkMerge() throws JSONRPCException, IOException { System.out.println(getId() + ": checkMerge()"); if (getState().containsKey("parent")) { System.out.println(getId() + ": Already merged, not doubling"); return; } if (neighbours == null) { neighbours = getNeighbours(); } ArrayList<Sub> subs = getState().get("subs", type); if (subs == null) { subs = new ArrayList<Sub>(0); } System.out.println(getId() + ": n:" + neighbours.size() + " - s:" + subs.size()); if (neighbours.size() - subs.size() == 1) { Set<String> nbs = new HashSet<String>(neighbours); int size = 1; for (Sub sub : subs) { nbs.remove(sub.getAddress()); size += sub.getSize(); } String neighbour = nbs.toArray(new String[0])[0]; getState().put("parent", neighbour); ObjectNode params = JOM.createObjectNode(); params.put("size", size); try { System.out.println(getId() + ": Merging with " + neighbour); Boolean res = callSync(URIUtil.create(neighbour), "merge", params, Boolean.class); if (!res) { getState().remove("parent"); schedule("checkMerge", null, (int) Math.random() * 500); } else { System.out.println(getId() + ": Merged with " + neighbour); } } catch (Exception e) { schedule("checkMerge", null, (int) Math.random() * 500); } } } public Boolean merge(@Name("size") int size, @Sender URI sender) throws JSONRPCException, IOException { if (neighbours == null) { neighbours = getNeighbours(); } String parent = getState().get("parent", String.class); if (parent != null && parent.equals(sender.toASCIIString())) { return false; } ArrayList<Sub> oldsubs = getState().get("subs", type); ArrayList<Sub> subs = null; if (oldsubs == null) { subs = new ArrayList<Sub>(); } else { subs = type.inject(oldsubs.clone()); } for (Sub sub : subs) { if (sub.getAddress().equals(sender)) { return true; } } if (!neighbours.contains(sender)) { System.err.println("Merge requested by non-neighbour??? : " + sender); return false; } Sub sub = new Sub(); sub.setAddress(sender.toASCIIString()); sub.setSize(size); subs.add(sub); if (!getState().putIfUnchanged("subs", subs, oldsubs)) { merge(size, sender); } schedule("checkMerge", null, 0); return true; } public void handleTask(@Name("count") Integer count, @Sender URI sender) throws IOException, JSONRPCException { if (sender != null && !getState().get("parent", String.class).equals(sender.toASCIIString())) { System.out.println("Warning: got task from non-parent!!!" + sender.toASCIIString()); } if (count > 0) { lampOn(); count--; } else { lampOff(); } ArrayList<Sub> subs = getState().get("subs", type); if (subs == null) { return; } for (Sub sub : subs) { int cnt = Math.min(count, sub.getSize()); count -= cnt; ObjectNode params = JOM.createObjectNode(); params.put("count", cnt); call(URI.create(sub.getAddress()), "handleTask", params, null); } } public void handleGoal(@Name("goal") Goal goal, @Sender URI sender) throws IOException, JSONRPCException, JsonProcessingException { String parent = getState().get("parent", String.class); if (parent != null) { System.err.println(getId() + ": HandleGoal received, sending it to my parent:" + parent); ObjectNode params = JOM.createObjectNode(); params.set("goal", JOM.getInstance().valueToTree(goal)); call(URIUtil.create(parent), "handleGoal", params, null); } else { System.err.println(getId() + ": HandleGoal received, handling it myself"); Set<String> nbs = new HashSet<String>(neighbours); ArrayList<Sub> subs = getState().get("subs", type); int subSize = 0; if (subs != null) { for (Sub sub : subs) { nbs.remove(sub.getAddress()); subSize += sub.getSize(); } } Integer pointer = getState().get(goal.getId(), Integer.class); if (pointer == null) { for (int i = 0; i < nbs.size(); i++) { if (nbs.toArray(new String[0])[i].equals(sender)) { pointer = i; } } if (pointer == null) { pointer = 0; } } Integer stepSize = getState().get("stepSize", Integer.class); if (!getState().containsKey(goal.getId())) { // Determine my own influence on the goal double noOn = (goal.getPercentage() * goal.getAgentCnt()) / 100; goal.setAgentCnt(goal.getAgentCnt() + subSize + 1); double max = (((noOn + subSize + 1) * 100) / (goal .getAgentCnt())); double min = (((noOn) * 100) / (goal.getAgentCnt())); int subOn = -1; if (max < goal.getGoalPct()) { subOn = subSize + 1; } else if (min > goal.getGoalPct()) { subOn = 0; } else { double noLampsOn = (goal.getGoalPct() * goal.getAgentCnt()) / 100; subOn = (int) Math.round(noLampsOn - noOn); } handleTask(subOn, null); goal.setPercentage((noOn + subOn) * 100 / goal.getAgentCnt()); goal.setTtl(0); } else { goal.setTtl(goal.getTtl() + 1); } getState().put("goal", goal); if (goal.getTtl() > 15) { // No changes, drop this goal. return; } if (nbs.size() == 0) { return; } // Send goal further to neighbours ObjectNode params = JOM.createObjectNode(); params.set("goal", JOM.getInstance().valueToTree(goal)); int count = 0; int original_pointer = pointer; boolean stop = false; while (count < stepSize && !stop) { String neighbour = nbs.toArray(new String[0])[pointer]; pointer++; if (pointer >= nbs.size()) { pointer = 0; } getState().put(goal.getId(), pointer); if (nbs.size() > 1) { if (neighbour.equals(sender)) { continue; } if (pointer == original_pointer) { stop = true; } } count++; call(URI.create(neighbour), "handleGoal", params, null); } } } class Sub { private int size = 0; private String address = ""; public Sub() {} public int getSize() { return size; } public void setSize(int size) { this.size = size; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } } }