package com.plectix.simulator.staticanalysis; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import com.plectix.simulator.interfaces.ConnectedComponentInterface; import com.plectix.simulator.simulationclasses.injections.Injection; /** * This class implements Agent entity. * @author avokhmin * */ public class Agent extends NamedEntity implements Comparable<Agent> { /** * idInConnectedComponent is the unique id in ConnectedComponent id is an * unique id for agent */ public static final int UNMARKED = -1; public static final String DEFAULT_NAME = "AGENT_DEFAULT_NAME"; private int idInConnectedComponent; private int idInRuleSide = UNMARKED; private final String name; private long id = -1; // TODO: is this field static or not??? private final Site defaultSite = new Site(Site.DEFAULT_NAME, this); private Map<String, Site> siteMap = new TreeMap<String, Site>(); /** * Constructor of Agent. * @param name name id of the new agent * @param agentId unique id of the new agent */ public Agent(String name, long agentId) { id = agentId; this.name = name.intern(); } /** * Empty Agent constructor */ public Agent() { id = -1; this.name = DEFAULT_NAME; } /** * This method takes an agent and finds all agents which somehow connected to it. * I.e. it finds connected component, containing this agent. * <br> NOTE: this method DOES NOT use link indexes! So we CAN use it during the simulation process * @param agent agent to find component for * @return connected component, containing this agent */ public final ConnectedComponentInterface getConnectedComponent() { Map<Long, Agent> adjacentAgents = new LinkedHashMap<Long, Agent>(); adjacentAgents.put(id, this); adjacentAgents = this.getAdjacentAgents(adjacentAgents); int index = 0; for (Agent agentIn : adjacentAgents.values()) { // TODO notice the line commented below // agentIn.setIdInRuleSide(index); agentIn.setIdInConnectedComponent(index++); } return new ConnectedComponent(adjacentAgents.values()); } private final Map<Long, Agent> getAdjacentAgents(Map<Long, Agent> agents) { Map<Long, Agent> allAgents = agents; Set<Agent> agentAddList = new LinkedHashSet<Agent>(); for (Site site : siteMap.values()) { Site siteLink = site.getLinkState().getConnectedSite(); if ((siteLink != null) && (!allAgents.keySet().contains(siteLink.getParentAgent().getId()))) { Agent agentLink = siteLink.getParentAgent(); agentAddList.add(agentLink); allAgents.put(agentLink.getId(), agentLink); } } for (Agent agentFromList : agentAddList) allAgents = agentFromList.getAdjacentAgents(allAgents); return allAgents; } /** * This method returns default site from current agent * @return default site from current agent */ public final Site getDefaultSite() { return defaultSite; } /** * This method returns <tt>true</tt>, if this agent already has injection equaivalent * to the given one, <tt>false</tt> * @param injection given injection * @return <tt>true</tt>, if this agent already has injection equivalent * to the given one, <tt>false</tt> */ public final boolean hasSimilarInjection(Injection injection) { ConnectedComponentInterface cc = injection.getConnectedComponent(); if (checkSites(this.getDefaultSite(), injection, cc)) return true; for (Site site : siteMap.values()) { if (checkSites(site.getParentAgent().getDefaultSite(), injection, cc)) return true; if (checkSites(site, injection, cc)) return true; } return false; } /** * This is utility for finding similar injections, used in {@link #hasSimilarInjection(Injection)} */ private final boolean checkSites(Site site, Injection injection, ConnectedComponentInterface cc) { List<Injection> sitesInjections = site.getInjectionFromLift(cc); if (sitesInjections.size() != 0) { if (injection.findInCollection(sitesInjections)) return true; } return false; } /** * * This method finds and agent, which is connected with this through the given site-collection * @param agent given agent * @param siteCollection collection of sites * @return agent (if there's one), which connected with current agent through the given sites, * otherwise <tt>null</tt> */ public final Agent findLinkAgent(Agent agent, List<Site> siteCollection) { if (agent == null || siteCollection.size() == 0) return null; Agent imageAgent = (Agent) this.getSiteByName(siteCollection.get(0).getName()) .getLinkState().getConnectedSite().getParentAgent(); for (Site siteF : siteCollection) { Agent agent2 = (Agent) this.getSiteByName(siteF.getName()) .getLinkState().getConnectedSite().getParentAgent(); if (imageAgent != agent2) return null; } if (imageAgent.equalz(agent)) return imageAgent; return null; } /** * This method adds site to this agent * @param site site we want to add */ public final void addSite(Site site) { site.setParentAgent(this); siteMap.put(site.getName(), site); } /** * This method indicates whether name ids of given agent is equal to name id of current one. * @param agent given agent */ public final boolean equalz(Agent agent) { if (this == agent) { return true; } if (agent == null) { return false; } return name.equals(agent.name); } /** * This method is some kind of override {@link Collection#contains(Object) contains}. * We need it just because we haven't override default {@link Object#equals(Object) equals}, * but we use our own {@link Agent#equalz(Agent) equalz}. So we had to create util * method for checking current agent in given collection * @param collection given collection */ public final boolean includedInCollection(Collection<Agent> collection) { for (Agent agent : collection) { if (this.equalz(agent)) { return true; } } return false; } /** * This method returns <tt>true</tt>, if sites from current agent are * {@link com.plectix.simulator.staticanalysis.Site#equalz(Site) equal} to sites * of the given agent, otherwise <tt>false</tt> * @param agent given agent * @return <tt>true</tt>, if sites from current agent are * {@link com.plectix.simulator.staticanalysis.Site#equalz(Site) equal} to sites * of the given agent, otherwise <tt>false</tt> */ public final boolean siteMapsAreEqual(Agent agent) { if (agent == null) { return false; } Set<Site> listThis = new LinkedHashSet<Site>(); Set<Site> listThat = new LinkedHashSet<Site>(); listThis.addAll(siteMap.values()); listThat.addAll(agent.getSites()); for (Site siteThis : siteMap.values()) { boolean containsCurrent = false; Site foundedSiteThat = null; for (Site siteThat : listThat) { if (siteThis.equalz(siteThat)) { foundedSiteThat = siteThat; containsCurrent = true; break; } } if (!containsCurrent) { return false; } else { listThis.remove(siteThis); listThat.remove(foundedSiteThat); } } return listThis.isEmpty() && listThat.isEmpty(); } //-------------------------GETTERS AND SETTERS--------------------------------------- /** * This method returns this agent's ordering number in left/right handside of rule * (if there is one), use only for create atomic actions for Rule. * @return ordering number in rule's handside, if there is such rule, or * -1 if there isn't */ public final int getIdInRuleHandside() { return idInRuleSide; } public final void setIdInRuleSide(int idInRuleSide) { this.idInRuleSide = idInRuleSide; } /** * This method searches site with similar id as given in current agent * @param siteName site id to search * @return site, that has similar id as given, or null, if there's no such */ public final Site getSiteByName(String siteName) { return siteMap.get(siteName); } /** * This method returns name of this agent * @see com.plectix.simulator.util.NameDictionary NameDictionary * @return name of this agent */ public final String getName() { return name; } /** * This method returns order number of this agent in connected component, * used only for create atomic actions for rule. */ public final int getIdInConnectedComponent() { return idInConnectedComponent; } /** * This method sets order number of this agent in connected component, * used only for create atomic actions for rule. * @param index new value */ public final void setIdInConnectedComponent(int index) { idInConnectedComponent = index; } /** * This method returns collection of current agent's sites */ public final Collection<Site> getSites() { return siteMap.values(); } /** * This method returns unique id of current agent * @return id of current agent */ public final long getId() { return id; } public final void setId(int id) { this.id = id; } public final void removeSite(String name) { siteMap.remove(name); } @Override public final int compareTo(Agent o) { return idInRuleSide - o.getIdInRuleHandside(); } @Override public final Agent clone(){ Agent agent = new Agent(name, -1); for (Site s : siteMap.values()) { agent.addSite(s.clone()); } return agent; } @Override public final String toString() { StringBuffer sb = new StringBuffer(getName() + "("); boolean first = true; for (Site site : siteMap.values()) { if (!first) { sb.append(", "); } else { first = false; } sb.append(site.getName()); if (!site.getInternalState().hasDefaultName()) { sb.append("~" + site.getInternalState().getName()); } if (site.getLinkState().getStatusLinkRank() == LinkRank.SEMI_LINK) { sb.append("!_"); } else if (site.getLinkIndex() != -1) { // sb.append("!" + site.getLinkIndex()); sb.append("!"); sb.append(site.getLinkState().getConnectedSite().getName()); sb.append(site.getLinkIndex()); } else if (site.getLinkState().getStatusLink() == LinkStatus.WILDCARD) { sb.append("?"); } } sb.append(")"); return sb.toString(); } @Override protected String getDefaultName() { return DEFAULT_NAME; } }