package jamel.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import jamel.data.DataManager; import jamel.data.Expression; /** * A basic sector. */ public class BasicSector extends JamelObject implements Sector { /** * Returns the specified action. * * @param phaseName * the name of the phase. * @param agentClass * the targeted Class of agents. * * @return the specified action. */ @SuppressWarnings("unchecked") private static Consumer<? super Agent> getAction(String phaseName, Class<? extends Agent> agentClass) { final Consumer<? super Agent> action; try { final Method getPhaseMethod = agentClass.getMethod("getAction", String.class); action = (Consumer<? super Agent>) getPhaseMethod.invoke(null, phaseName); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { throw new RuntimeException("Something went wrong while creating the action phase \"" + phaseName + "\" for the agent \"" + agentClass.getName() + "\".", e); } return action; } /** * The class of the agents that populate the sector. */ final private Class<? extends Agent> agentClass; /** * The collection of agents that populate this sector. */ final private List<Agent> agents; /** * The data manager. */ final private DataManager dataManager; /** * To count the agent creation since the start. */ private int nAgent = 0; /** * The name of the sector. */ final private String name; /** * The specification of the sector. */ final private Element specification; /** * Creates a new basic sector. * * @param specification * an XML element that contains the specification of the sector. * * @param simulation * the parent simulation. */ public BasicSector(final Element specification, final Simulation simulation) { super(simulation); this.specification = specification; this.name = this.specification.getAttribute("name"); // Inits the type of the agents. { final NodeList nodeList = this.specification.getElementsByTagName("agentClassName"); if (nodeList.getLength() == 0) { throw new RuntimeException("Missing tag : agentClassName"); } final String agentClassName = nodeList.item(0).getTextContent().trim(); try { final Class<?> klass = Class.forName(agentClassName); if (!Agent.class.isAssignableFrom(klass)) { throw new RuntimeException("Agent class is not assignable from " + klass.getName()); // TODO c'est une erreur du scénario : à traiter comme // telle. Balancer un message d'erreur à la GUI qui display // une box. } @SuppressWarnings("unchecked") final Class<? extends Agent> klass2 = (Class<? extends Agent>) klass; this.agentClass = klass2; } catch (ClassNotFoundException e) { throw new RuntimeException("Something went wrong while creating the sector \'" + this.name + "\'", e); } } // Looks for the initial number of agents. { final NodeList nodeList = this.specification.getElementsByTagName("initialPopulation"); final int initialPopulation; if (nodeList.getLength() == 0) { initialPopulation = 0; } else { initialPopulation = Integer.parseInt(nodeList.item(0).getTextContent().trim()); } this.agents = new ArrayList<>(getNewAgents(initialPopulation)); } this.dataManager = new DataManager(this.agents, this); } /** * Creates and returns a collection of new agents. * * @param number * the number of agents to be created. * @return a collection of new agents. */ private Collection<Agent> getNewAgents(final int number) { final Collection<Agent> result = new LinkedList<>(); for (int i = 0; i < number; i++) { try { result.add(agentClass.getConstructor(Sector.class, int.class).newInstance(this, this.nAgent)); this.nAgent++; } catch (Exception e) { throw new RuntimeException("Something went wrong while creating a new agent.", e); } } return result; } @Override public void doEvent(Element event) { throw new RuntimeException("Not yet implemented: " + event.getTagName()); } @Override public Expression getDataAccess(String[] args) { return this.dataManager.getDataAccess(args); } @Override public String getName() { return this.name; } @Override public Phase getPhase(final String phaseName, final boolean shuffle) { if (phaseName == null) { throw new RuntimeException("Phase name is null"); } final Consumer<? super Agent> action = getAction(phaseName, agentClass); final Phase result = new Phase() { @Override public String getName() { return phaseName; } @Override public Sector getSector() { return BasicSector.this; } @Override public void run() { if (shuffle) { Collections.shuffle(BasicSector.this.agents, BasicSector.this.getRandom()); } BasicSector.this.agents.forEach(action); } }; return result; } @Override public Agent[] select(int n) { Agent[] result = new Agent[n]; for (int i = 0; i < n; i++) { result[i] = this.agents.get(this.getRandom().nextInt(this.agents.size())); for (int j = 0; j < i - 1; j++) { // Si l'agent est déjà dans la sélection, on l'efface. if (result[j] == result[i]) { result[i] = null; } } } return result; } }