From 548593631e259523229afe0b8f95ffefc8212e26 Mon Sep 17 00:00:00 2001 From: Andre Correa Date: Wed, 18 Jun 2025 00:14:09 -0300 Subject: [PATCH 1/9] fix sonar issues on Ballot.java --- src/main/java/election_structure/Ballot.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/election_structure/Ballot.java b/src/main/java/election_structure/Ballot.java index c99ea61..9545cc0 100644 --- a/src/main/java/election_structure/Ballot.java +++ b/src/main/java/election_structure/Ballot.java @@ -95,13 +95,13 @@ private void setupBallot () { e.printStackTrace(); } - if ( registeredCandidates.size() < 1 || registeredVoters.size() < 2 ) { + if ( registeredCandidates.isEmpty() || registeredVoters.size() < 2 ) { logger.log(Level.WARNING, String.format("%s THERE CANNOT BE AN ELECTION WITH NO CANDIDATES OR NOT ENOUGH QUORUM %s", ANSI_YELLOW, ANSI_RESET)); ACLMessage msg = new ACLMessage(ACLMessage.INFORM); ArrayList foundMediators = findMediators( new String[]{ Integer.toString(votingCode) } ); - if ( foundMediators.size() > 0 ) { + if ( !foundMediators.isEmpty() ) { for ( DFAgentDescription fndMed : foundMediators ) { msg.addReceiver(fndMed.getName()); } @@ -123,7 +123,7 @@ private void startElection () { ACLMessage msg = new ACLMessage(ACLMessage.INFORM); ArrayList foundMediators = findMediators( new String[]{ Integer.toString(votingCode) } ); - if ( foundMediators.size() > 0 ) { + if ( !foundMediators.isEmpty() ) { for ( DFAgentDescription fndMed : foundMediators ) { msg.addReceiver(fndMed.getName()); } From a5c5cdba9dd4d2436cb295e890fde00314bd39f8 Mon Sep 17 00:00:00 2001 From: Andre Correa Date: Wed, 18 Jun 2025 00:14:25 -0300 Subject: [PATCH 2/9] fix sonar issues on Mediator.java --- .../java/election_structure/Mediator.java | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/main/java/election_structure/Mediator.java b/src/main/java/election_structure/Mediator.java index 647d954..539467c 100644 --- a/src/main/java/election_structure/Mediator.java +++ b/src/main/java/election_structure/Mediator.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Hashtable; +import java.util.Map; import java.util.Stack; import java.util.logging.Level; @@ -101,8 +102,8 @@ public void action () { ACLMessage msg2 = msg.createReply(); StringBuilder strBld = new StringBuilder(); - for ( Types type : votingWeights.keySet() ) { - strBld.append(String.format("%s %d ", type.toString(), votingWeights.get(type))); + for ( Map.Entry entry : votingWeights.entrySet() ) { + strBld.append(String.format("%s %d ", entry.getKey().toString(), entry.getValue())); } msg2.setContent(String.format("VOTEID %d WEIGHTS %d %s", votingCode, votingWeights.size(), strBld.toString().trim())); @@ -183,33 +184,35 @@ protected WakerBehaviour timeoutBehaviour( String motivation, long timeout) { @Override protected void onWake() { - if ( motivation.equals("registration") ) { - if(!ballotRequested){ + if ( motivation.equals("registration") && !ballotCreated) { logger.log(Level.WARNING, String.format("%s Agent registration timed out! %s", ANSI_YELLOW, ANSI_RESET)); createBallot(); - } - } else if (motivation.equals("Create-Ballot")){ - if(!ballotCreated){ + } else if (motivation.equals("Create-Ballot") && !ballotCreated){ logger.log(Level.WARNING, String.format("%s Ballot creation timed out! %s", ANSI_YELLOW, ANSI_RESET)); createBallot(); - } } } }; } private void informWinner(){ - + /* + * TODO: when finished election broadcast the winner + */ } protected void resetVoting(Agent myAgent){ - + /* + * TODO: when finished election reset all data + */ } private void computeResults() { - + /* + * TODO: move to ballot agent + */ } private void deleteElection (int receivedVotingCode) { @@ -287,12 +290,12 @@ private void genCandidateCodes() { private void informCandidatesProposals ( ArrayList foundVotingParticipants ) { ACLMessage msg = new ACLMessage(ACLMessage.INFORM); - foundVotingParticipants.forEach(vot -> { - msg.addReceiver(vot.getName()); - }); + foundVotingParticipants.forEach(vot -> + msg.addReceiver(vot.getName()) + ); - for ( AID candAID : candidatures.keySet() ) { - Candidature cdtr = candidatures.get(candAID); + for ( Map.Entry entry : candidatures.entrySet() ) { + Candidature cdtr = entry.getValue(); String content = String.format("CANDIDATE %d %s %s", cdtr.candidatureNumber, PROPOSAL, cdtr.proposal); msg.setContent(content); From 092250950ff098db93dbdc47b8ce08e7e5a0379b Mon Sep 17 00:00:00 2001 From: Andre Correa Date: Wed, 18 Jun 2025 00:19:28 -0300 Subject: [PATCH 3/9] fix sonar issues on Voter.java --- src/main/java/election_structure/Voter.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/election_structure/Voter.java b/src/main/java/election_structure/Voter.java index 421e16e..6af233a 100644 --- a/src/main/java/election_structure/Voter.java +++ b/src/main/java/election_structure/Voter.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.Hashtable; import java.util.List; +import java.util.Map; import java.util.logging.Level; import jade.core.AID; @@ -73,7 +74,7 @@ public void action () { try { AID foundMediator = null; - if ( foundAgents.size() > 0 ) { + if ( !foundAgents.isEmpty() ) { foundMediator = foundAgents.get(0).getName(); msg2.addReceiver(foundMediator); @@ -196,7 +197,7 @@ private void informVotingRegistration() { String sendMsg = String.format("%s IN %d", REGISTERED, votingCode); - if ( candidate == true ) + if ( candidate ) sendMsg += " AND CANDIDATE"; informMsg.setContent(sendMsg); @@ -263,20 +264,21 @@ private void vote(){ private String chooseVote(){ - String selectedCandidate = new String(); + String selectedCandidate = ""; - int max =-1, min = Integer.MAX_VALUE; + int max =-1; + int min = Integer.MAX_VALUE; int len; - for(String candID : recvProposals.keySet()){ - len = recvProposals.get(candID).length(); + for(Map.Entry entry : recvProposals.entrySet()){ + len = entry.getValue().length(); if(len > max && selectionMethod == 1){ max = len; - selectedCandidate = candID; + selectedCandidate = entry.getKey(); } if(len < min && selectionMethod == 0){ min = len; - selectedCandidate = candID; + selectedCandidate = entry.getKey(); } } From 01b8576310f87057c64e463de98ae2049d693e87 Mon Sep 17 00:00:00 2001 From: Andre Correa Date: Wed, 18 Jun 2025 02:23:16 -0300 Subject: [PATCH 4/9] :sparkles: implements computation of votes and sending to mediator --- src/main/java/election_structure/Ballot.java | 118 +++++++++++++++++- .../java/election_structure/Mediator.java | 21 ++-- src/main/java/election_structure/Voter.java | 2 +- 3 files changed, 130 insertions(+), 11 deletions(-) diff --git a/src/main/java/election_structure/Ballot.java b/src/main/java/election_structure/Ballot.java index 9545cc0..dbb8ac4 100644 --- a/src/main/java/election_structure/Ballot.java +++ b/src/main/java/election_structure/Ballot.java @@ -2,12 +2,16 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import jade.core.AID; import jade.core.behaviours.OneShotBehaviour; +import jade.core.behaviours.WakerBehaviour; import jade.domain.FIPAAgentManagement.DFAgentDescription; import jade.domain.FIPAAgentManagement.ServiceDescription; import jade.lang.acl.ACLMessage; @@ -17,9 +21,15 @@ public class Ballot extends BaseAgent { private Hashtable registeredVoters; private ArrayList registeredCandidates; - private Hashtable receivedVotes; + private Hashtable> receivedVotes; private Hashtable votingWeights; + AtomicInteger receivedVotesCnt; + + Boolean votesCollected = false; + + private final Object lock = new Object(); + @Override protected void setup() { @@ -28,7 +38,9 @@ protected void setup() { logger.log(Level.INFO, "I'm the ballot!"); this.registerDF(this, "Ballot", "ballot"); - + receivedVotes = new Hashtable<>(); + + receivedVotesCnt = new AtomicInteger(0); addBehaviour(handleMessages()); ArrayList foundAgent = new ArrayList<>( @@ -60,7 +72,29 @@ public void action () { } setupBallot(); - } else { + + } else if (msg.getContent().startsWith(Integer.toString(votingCode))) { + Types voterType = registeredVoters.get(msg.getSender()); + int vote = Integer.parseInt(splittedMsg[1]); + + synchronized(lock){ + Map updateMap = receivedVotes.get(vote); + + if (updateMap == null) updateMap = new HashMap(); + + updateMap.put(voterType, updateMap.get(voterType) == null? 1 : updateMap.get(voterType) + 1); + receivedVotes.put(vote, updateMap); + + if(receivedVotesCnt.incrementAndGet() == 1){ + addBehaviour(timeoutBehaviour("collectVotes", TIMEOUT_LIMIT*3)); + } + + if(receivedVotesCnt.get() == registeredVoters.size()){ + votesCollected = true; + computeResults(); + } + } + } else { logger.log(Level.INFO, String.format("%s %s %s", getLocalName(), UNEXPECTED_MSG, msg.getSender().getLocalName())); } @@ -68,6 +102,23 @@ public void action () { }; } + @Override + protected WakerBehaviour timeoutBehaviour( String motivation, long timeout) { + return new WakerBehaviour(this, timeout) { + private static final long serialVersionUID = 1L; + + @Override + protected void onWake() { + if ( motivation.equals("collectVotes") && !votesCollected) { + votesCollected = true; + logger.log(Level.WARNING, + String.format("%s Agent voting time window ended! %s", ANSI_YELLOW, ANSI_RESET)); + computeResults(); + } + } + }; + } + private void setupBallot () { receivedVotes = new Hashtable<>(); registeredCandidates = new ArrayList<>(); @@ -136,4 +187,65 @@ private void startElection () { e.printStackTrace(); } } + + private void computeResults() { + HashMap results = new HashMap<>(); + + int sum; + + int maxVote = -1; + + ArrayList winnerCandidates = new ArrayList<>(); + + for(Map.Entry> entry : receivedVotes.entrySet()){ + sum = 0; + Map votesCount = entry.getValue(); + + for(Map.Entry entry2 : votesCount.entrySet()){ + sum += votingWeights.get(entry2.getKey()) * entry2.getValue(); + } + + results.put(entry.getKey(), sum); + + if(sum == maxVote){ + winnerCandidates.add(entry.getKey()); + } + + if(sum > maxVote){ + maxVote = sum; + winnerCandidates.clear(); + winnerCandidates.add(entry.getKey()); + } + + } + + System.out.println("WEIGHTS: "); + for(Map.Entry entry : votingWeights.entrySet()){ + System.out.println("Key: " + entry.getKey() + " Weight: " + entry.getValue()); + } + System.out.println("WINNER: " + winnerCandidates + " VoteCount: " + maxVote); + + ACLMessage msg = new ACLMessage(ACLMessage.INFORM); + + msg.addReceiver(findMediators(new String[]{ Integer.toString(votingCode) }).get(0).getName()); + + StringBuilder strBld = new StringBuilder(); + for ( Integer winner : winnerCandidates ) { + strBld.append(String.format("%d ", winner)); + } + + String winners = strBld.toString().trim(); + msg.setContent(String.format("%s WinnersCount %d VotesCount %d Winners %s", "RESULTS", winnerCandidates.size(), maxVote, winners)); + send(msg); + + strBld.setLength(0); + for ( Map.Entry entry : results.entrySet() ) { + strBld.append(String.format("%d %d ", entry.getKey(), entry.getValue())); + } + + String voteLog = strBld.toString().trim(); + msg.setContent(String.format("%s Size %d %s", "ELECTIONLOG", results.size(),voteLog)); + send(msg); + + } } diff --git a/src/main/java/election_structure/Mediator.java b/src/main/java/election_structure/Mediator.java index 539467c..0f294e8 100644 --- a/src/main/java/election_structure/Mediator.java +++ b/src/main/java/election_structure/Mediator.java @@ -124,6 +124,19 @@ public void action () { e.printStackTrace(); } + } else if(msg.getContent().startsWith("RESULTS") ) { + + System.out.println(msg.getContent()); + /* + * TODO: implement what to do with the results + */ + + } else if(msg.getContent().startsWith("ELECTIONLOG") ) { + + System.out.println(msg.getContent()); + /* + * TODO: implement what to do with the logs + */ } else { logger.log(Level.INFO, String.format("%s RECEIVED AN UNEXPECTED MESSAGE FROM %s", getLocalName(), msg.getSender().getLocalName())); @@ -209,12 +222,6 @@ protected void resetVoting(Agent myAgent){ */ } - private void computeResults() { - /* - * TODO: move to ballot agent - */ - } - private void deleteElection (int receivedVotingCode) { logger.log(Level.INFO, String.format("%s DELETING ELECTION WITH CODE %d %s", ANSI_CYAN, receivedVotingCode, ANSI_RESET)); @@ -227,7 +234,7 @@ private void setupVotingWeights () { votingWeights = new Hashtable<>(); for ( Types element : Types.values() ) { - votingWeights.put(element, rand.nextInt(5)); + votingWeights.put(element, rand.nextInt(1,6)); } } diff --git a/src/main/java/election_structure/Voter.java b/src/main/java/election_structure/Voter.java index 6af233a..f753b28 100644 --- a/src/main/java/election_structure/Voter.java +++ b/src/main/java/election_structure/Voter.java @@ -23,7 +23,7 @@ public class Voter extends BaseAgent { private Hashtable recvProposals; private int candidatesCount; private int candidatesExpected; - int selectionMethod; + private int selectionMethod; @Override protected void setup() { From d3705ece7ac1acfd729385e14461c055cb5bacee Mon Sep 17 00:00:00 2001 From: Andre Correa Date: Wed, 18 Jun 2025 02:33:01 -0300 Subject: [PATCH 5/9] fix sonar issues on Ballot.java --- src/main/java/election_structure/Ballot.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/election_structure/Ballot.java b/src/main/java/election_structure/Ballot.java index dbb8ac4..fdd7e31 100644 --- a/src/main/java/election_structure/Ballot.java +++ b/src/main/java/election_structure/Ballot.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.EnumMap; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; @@ -24,11 +25,11 @@ public class Ballot extends BaseAgent { private Hashtable> receivedVotes; private Hashtable votingWeights; - AtomicInteger receivedVotesCnt; + private AtomicInteger receivedVotesCnt; - Boolean votesCollected = false; + private Boolean votesCollected = false; - private final Object lock = new Object(); + private final transient Object lock = new Object(); @Override protected void setup() { @@ -80,7 +81,7 @@ public void action () { synchronized(lock){ Map updateMap = receivedVotes.get(vote); - if (updateMap == null) updateMap = new HashMap(); + if (updateMap == null) updateMap = new EnumMap<>(Types.class); updateMap.put(voterType, updateMap.get(voterType) == null? 1 : updateMap.get(voterType) + 1); receivedVotes.put(vote, updateMap); @@ -218,12 +219,6 @@ private void computeResults() { } } - - System.out.println("WEIGHTS: "); - for(Map.Entry entry : votingWeights.entrySet()){ - System.out.println("Key: " + entry.getKey() + " Weight: " + entry.getValue()); - } - System.out.println("WINNER: " + winnerCandidates + " VoteCount: " + maxVote); ACLMessage msg = new ACLMessage(ACLMessage.INFORM); From 82ab694c3374f6feae26df7ef300eb9798e960ea Mon Sep 17 00:00:00 2001 From: Andre Correa Date: Sun, 22 Jun 2025 20:29:03 -0300 Subject: [PATCH 6/9] :sparkles: add null vote options Co-authored-by: gabrielm2q --- src/main/java/election_structure/Ballot.java | 8 +++++--- src/main/java/election_structure/Mediator.java | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/election_structure/Ballot.java b/src/main/java/election_structure/Ballot.java index fdd7e31..5feec07 100644 --- a/src/main/java/election_structure/Ballot.java +++ b/src/main/java/election_structure/Ballot.java @@ -20,7 +20,7 @@ public class Ballot extends BaseAgent { private Hashtable registeredVoters; - private ArrayList registeredCandidates; + private Hashtable registeredCandidates; private Hashtable> receivedVotes; private Hashtable votingWeights; @@ -77,6 +77,8 @@ public void action () { } else if (msg.getContent().startsWith(Integer.toString(votingCode))) { Types voterType = registeredVoters.get(msg.getSender()); int vote = Integer.parseInt(splittedMsg[1]); + + if(!registeredCandidates.containsKey(vote)) vote = -1; synchronized(lock){ Map updateMap = receivedVotes.get(vote); @@ -122,7 +124,7 @@ protected void onWake() { private void setupBallot () { receivedVotes = new Hashtable<>(); - registeredCandidates = new ArrayList<>(); + registeredCandidates = new Hashtable<>(); registeredVoters = new Hashtable<>(); ArrayList foundVoters = new ArrayList<>( @@ -138,7 +140,7 @@ private void setupBallot () { if ( Arrays.toString(Types.values()).contains(el.getName()) ) { registeredVoters.put(voter.getName(), Types.valueOf(el.getName())); } else if ( el.getName().equals("Candidate") ) { - registeredCandidates.add(voter.getName()); + registeredCandidates.put( Integer.parseInt(el.getType()), voter.getName()); } } } diff --git a/src/main/java/election_structure/Mediator.java b/src/main/java/election_structure/Mediator.java index 0f294e8..3ab6fef 100644 --- a/src/main/java/election_structure/Mediator.java +++ b/src/main/java/election_structure/Mediator.java @@ -126,6 +126,7 @@ public void action () { } else if(msg.getContent().startsWith("RESULTS") ) { + System.out.println(msg.getContent()); /* * TODO: implement what to do with the results From 54e2b5ca63c2ba5c6e5109bc1d1f2249f810fc4c Mon Sep 17 00:00:00 2001 From: Andre Correa Date: Sun, 22 Jun 2025 21:15:00 -0300 Subject: [PATCH 7/9] :sparkles: add results log Co-authored-by: gabrielm2q --- .../java/election_structure/Mediator.java | 55 +++++++++++++------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/src/main/java/election_structure/Mediator.java b/src/main/java/election_structure/Mediator.java index 3ab6fef..a617333 100644 --- a/src/main/java/election_structure/Mediator.java +++ b/src/main/java/election_structure/Mediator.java @@ -24,10 +24,8 @@ public class Mediator extends BaseAgent { private int totalQuorum = 0; private Boolean ballotCreated = false; private Boolean ballotRequested = false; - - private Hashtable votingLog; + private Hashtable candidatures; - private ArrayList winners; private ArrayList preCandidates; private Stack candidateCodes; @@ -53,9 +51,6 @@ public void action () { if (msg.getContent().startsWith(START)) { votingCode = votingCodeGenerator(); - - votingLog = new Hashtable<>(); - winners = new ArrayList<>(); setupVotingWeights(); genCandidateCodes(); @@ -126,18 +121,30 @@ public void action () { } else if(msg.getContent().startsWith("RESULTS") ) { + informWinner(msg.getContent()); System.out.println(msg.getContent()); - /* - * TODO: implement what to do with the results - */ + + String winnersCnt = splittedMsg[2]; + String winnersVote = splittedMsg[4]; + + String winnersCode = ""; + + for(int i = 6; i < splittedMsg.length; i++){ + winnersCode += splittedMsg[i] + " "; + } + + String results = String.format(" ELECTION RESULTS FOR VOTING %d: \n", votingCode); + results = results.concat(String.format(" \t\tWinner count: %s\n",winnersCnt)); + results = results.concat(String.format(" \t\tWinner received votes %s\n", winnersVote)); + results = results.concat(String.format(" \t\tWinner Codes: %s ", winnersCode)); + + logger.log(Level.INFO, String.format("%s%s%s", ANSI_PURPLE, results, ANSI_RESET)); } else if(msg.getContent().startsWith("ELECTIONLOG") ) { - System.out.println(msg.getContent()); - /* - * TODO: implement what to do with the logs - */ + logger.log(Level.INFO, String.format("%s %s %s", ANSI_PURPLE, msg.getContent(), ANSI_RESET)); + } else { logger.log(Level.INFO, String.format("%s RECEIVED AN UNEXPECTED MESSAGE FROM %s", getLocalName(), msg.getSender().getLocalName())); @@ -211,10 +218,24 @@ protected void onWake() { }; } - private void informWinner(){ - /* - * TODO: when finished election broadcast the winner - */ + private void informWinner(String content){ + ACLMessage msg2 = new ACLMessage(ACLMessage.INFORM); + + ArrayList foundVotingParticipants; + String [] types = { Integer.toString(votingCode), "voter" }; + + foundVotingParticipants = new ArrayList<>( + Arrays.asList(searchAgentByType(types))); + + foundVotingParticipants.forEach(vot -> + msg2.addReceiver(vot.getName()) + ); + + msg2.setContent(content); + send(msg2); + + logger.log(Level.INFO, + String.format("%s %s SENT ELECTION RESULTS TO ALL VOTERS! %s", ANSI_PURPLE , getLocalName(), ANSI_RESET)); } protected void resetVoting(Agent myAgent){ From f988c3df470a02a4697320a2c9bde40255acdb9e Mon Sep 17 00:00:00 2001 From: gabrielm2q Date: Sun, 22 Jun 2025 21:48:10 -0300 Subject: [PATCH 8/9] :sparkles: adds voter logic for receiving election results Co-authored-by: dartmol203 --- src/main/java/election_structure/Mediator.java | 2 -- src/main/java/election_structure/Voter.java | 14 +++++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/java/election_structure/Mediator.java b/src/main/java/election_structure/Mediator.java index a617333..47242a6 100644 --- a/src/main/java/election_structure/Mediator.java +++ b/src/main/java/election_structure/Mediator.java @@ -122,8 +122,6 @@ public void action () { } else if(msg.getContent().startsWith("RESULTS") ) { informWinner(msg.getContent()); - - System.out.println(msg.getContent()); String winnersCnt = splittedMsg[2]; String winnersVote = splittedMsg[4]; diff --git a/src/main/java/election_structure/Voter.java b/src/main/java/election_structure/Voter.java index f753b28..ca626ee 100644 --- a/src/main/java/election_structure/Voter.java +++ b/src/main/java/election_structure/Voter.java @@ -24,6 +24,7 @@ public class Voter extends BaseAgent { private int candidatesCount; private int candidatesExpected; private int selectionMethod; + private int myCandidatureCode = -1;; @Override protected void setup() { @@ -93,6 +94,7 @@ public void action () { votingCode = Integer.parseInt(splittedMsg[1]); recvProposals = new Hashtable<>(); candidatesCount = 0; + myCandidatureCode = -1; registerDF(myAgent, Integer.toString(votingCode), Integer.toString(votingCode)); @@ -136,12 +138,22 @@ public void action () { requestCandidateCode(); } else if ( msg.getContent().startsWith("CANDIDCODE") ) { - registerCandidature(myAgent, Integer.parseInt(splittedMsg[1]), msg); + myCandidatureCode = Integer.parseInt(splittedMsg[1]); + registerCandidature(myAgent, myCandidatureCode, msg); } else if ( msg.getContent().startsWith("CANDIDATE") ) { String prop = msg.getContent().substring(msg.getContent().indexOf(PROPOSAL) + PROPOSAL.length() + 1); recvProposals.put(splittedMsg[1], prop); candidatesCount++; + } else if ( msg.getContent().startsWith("RESULTS") ) { + String logContent = String.format("%s RECEIVED THE RESULTS OF ELECTION %d!", getLocalName(), votingCode); + + for( int i = 6; i < splittedMsg.length; i++ ){ + if ( candidate && Integer.parseInt(splittedMsg[i]) == myCandidatureCode ) + logContent = String.format("%s I'M %s AND I WON THE ELECTION WITH CODE %d! %s", ANSI_GREEN, getLocalName(), votingCode, ANSI_RESET); + } + + logger.log(Level.INFO, logContent); } else { logger.log(Level.INFO, String.format("%s %s %s", getLocalName(), UNEXPECTED_MSG, msg.getSender().getLocalName())); From 4aa86d30a25fbfba76b0d9c078156b9233e46df3 Mon Sep 17 00:00:00 2001 From: gabrielm2q Date: Sun, 22 Jun 2025 23:55:55 -0300 Subject: [PATCH 9/9] :sparkles: adds election reset logic Co-authored-by: dartmol203 --- Makefile | 9 +-- src/main/java/election_structure/App.java | 1 - .../java/election_structure/BaseAgent.java | 1 - .../java/election_structure/Mediator.java | 63 ++++++++++++++----- src/main/java/election_structure/Voter.java | 8 --- 5 files changed, 49 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index 5d14f01..47a1a35 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,8 @@ QUORUM ?= 3 -MALFUNCTION ?= 0 DF_MAX_RESULT := $(shell expr $(QUORUM) + 5) PATH_PROJECT_JAR = target/election_structure-0.0.1-SNAPSHOT.jar PROJECT_GROUP = election_structure -JADE_AGENTS = election_structure:$(PROJECT_GROUP).App($(QUORUM), $(MALFUNCTION)); +JADE_AGENTS = election_structure:$(PROJECT_GROUP).App($(QUORUM)); JADE_FLAGS = -gui -jade_domain_df_maxresult $(DF_MAX_RESULT) -agents "$(JADE_AGENTS)" .PHONY: @@ -40,7 +39,5 @@ help: @echo " $$ make help" @echo " Shows this help resume" @echo "" - @echo "If wanted it's possible to change the quantity of agents by adding the variable QUORUM to the command, as seen in the next line" - @echo " $$ make build-and-run QUORUM=" - @echo "It's possible to activate a random agent malfunction to test timeout more effectively, as seen in the next line" - @echo " $$ make build-and-run MALFUNCTION=1" \ No newline at end of file + @echo "If wanted it's possible to change the quantity of agents by adding the variable QUORUM (with a value equal or greater than 1) to the command, as seen in the next line" + @echo " $$ make build-and-run QUORUM=" \ No newline at end of file diff --git a/src/main/java/election_structure/App.java b/src/main/java/election_structure/App.java index 2f2439c..e485e81 100644 --- a/src/main/java/election_structure/App.java +++ b/src/main/java/election_structure/App.java @@ -36,7 +36,6 @@ protected void setup() { int votersQuorum = 0; if (args != null && args.length > 0) { votersQuorum = Integer.parseInt(args[0].toString()); - randomAgentMalfunction = (Integer.parseInt(args[1].toString()) > 0); } int votingStarter = rand.nextInt(votersQuorum); diff --git a/src/main/java/election_structure/BaseAgent.java b/src/main/java/election_structure/BaseAgent.java index 568ba1b..0fee5df 100644 --- a/src/main/java/election_structure/BaseAgent.java +++ b/src/main/java/election_structure/BaseAgent.java @@ -62,7 +62,6 @@ public abstract class BaseAgent extends Agent { protected static final Logger logger = Logger.getLogger(BaseAgent.class.getName()); protected static final Long TIMEOUT_LIMIT = 1000L; - protected static boolean randomAgentMalfunction = false; protected boolean brokenAgent = false; protected boolean candidate = false; diff --git a/src/main/java/election_structure/Mediator.java b/src/main/java/election_structure/Mediator.java index 47242a6..b3d2492 100644 --- a/src/main/java/election_structure/Mediator.java +++ b/src/main/java/election_structure/Mediator.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Hashtable; +import java.util.Iterator; import java.util.Map; import java.util.Stack; import java.util.logging.Level; @@ -12,7 +13,10 @@ import jade.core.Agent; import jade.core.behaviours.OneShotBehaviour; import jade.core.behaviours.WakerBehaviour; +import jade.domain.DFService; +import jade.domain.FIPAException; import jade.domain.FIPAAgentManagement.DFAgentDescription; +import jade.domain.FIPAAgentManagement.ServiceDescription; import jade.lang.acl.ACLMessage; public class Mediator extends BaseAgent { @@ -70,9 +74,6 @@ public void action () { candidatures = new Hashtable<>(); preCandidates = new ArrayList<>(); - - - } else if ( msg.getContent().startsWith(INFORM) ) { if (splittedMsg[1].equals(QUORUM)) { addBehaviour(timeoutBehaviour( "registration", TIMEOUT_LIMIT)); @@ -104,7 +105,7 @@ public void action () { msg2.setContent(String.format("VOTEID %d WEIGHTS %d %s", votingCode, votingWeights.size(), strBld.toString().trim())); send(msg2); } else if ( msg.getContent().startsWith("FAILURE") ) { - deleteElection(Integer.parseInt(splittedMsg[1])); + resetElection(myAgent); } else if ( msg.getContent().startsWith("READY") ) { try { int votCode = Integer.parseInt(splittedMsg[1]); @@ -140,9 +141,8 @@ public void action () { logger.log(Level.INFO, String.format("%s%s%s", ANSI_PURPLE, results, ANSI_RESET)); } else if(msg.getContent().startsWith("ELECTIONLOG") ) { - logger.log(Level.INFO, String.format("%s %s %s", ANSI_PURPLE, msg.getContent(), ANSI_RESET)); - + resetElection(myAgent); } else { logger.log(Level.INFO, String.format("%s RECEIVED AN UNEXPECTED MESSAGE FROM %s", getLocalName(), msg.getSender().getLocalName())); @@ -203,11 +203,11 @@ protected WakerBehaviour timeoutBehaviour( String motivation, long timeout) { @Override protected void onWake() { - if ( motivation.equals("registration") && !ballotCreated) { + if ( votingCode != -1 && motivation.equals("registration") && !ballotCreated ) { logger.log(Level.WARNING, String.format("%s Agent registration timed out! %s", ANSI_YELLOW, ANSI_RESET)); createBallot(); - } else if (motivation.equals("Create-Ballot") && !ballotCreated){ + } else if ( votingCode != -1 && motivation.equals("Create-Ballot") && !ballotCreated ){ logger.log(Level.WARNING, String.format("%s Ballot creation timed out! %s", ANSI_YELLOW, ANSI_RESET)); createBallot(); @@ -236,20 +236,49 @@ private void informWinner(String content){ String.format("%s %s SENT ELECTION RESULTS TO ALL VOTERS! %s", ANSI_PURPLE , getLocalName(), ANSI_RESET)); } - protected void resetVoting(Agent myAgent){ - /* - * TODO: when finished election reset all data - */ + protected void resetElection(Agent myAgent){ + registeredQuorum = 0; + totalQuorum = 0; + ballotCreated = false; + ballotRequested = false; + + candidatures = new Hashtable<>(); + preCandidates = new ArrayList<>(); + candidateCodes = new Stack<>(); + + deleteAgentServices(myAgent, Integer.toString(votingCode), Integer.toString(votingCode)); + deleteAgentServices(myAgent, "voter", "Candidate"); + + votingCode = -1; + + logger.log(Level.WARNING, ANSI_YELLOW + "VOTING ENDED!" + ANSI_RESET); } - private void deleteElection (int receivedVotingCode) { - logger.log(Level.INFO, String.format("%s DELETING ELECTION WITH CODE %d %s", ANSI_CYAN, receivedVotingCode, ANSI_RESET)); + private void deleteAgentServices(Agent myAgent, String searchAttr, String deleteCondition) { + DFAgentDescription[] dfd = searchAgentByType(searchAttr); + + for (int i = 0; i < dfd.length; i++) { + Iterator it = dfd[i].getAllServices(); - /* - * HERE, WE SHOULD IMPLEMENT VOTING DELETION LOGIC - */ + ServiceDescription sd; + while (it.hasNext()) { + sd = it.next(); + if( sd.getType().equals(deleteCondition) || sd.getName().equals(deleteCondition) ){ + dfd[i].removeServices(sd); + break; + } + } + + try { + DFService.modify(myAgent, dfd[i]); + } catch (FIPAException e) { + logger.log(Level.SEVERE, ANSI_RED + "ERROR WHILE MODIFYING AGENTS" + ANSI_RESET); + e.printStackTrace(); + } + } } + private void setupVotingWeights () { votingWeights = new Hashtable<>(); diff --git a/src/main/java/election_structure/Voter.java b/src/main/java/election_structure/Voter.java index ca626ee..45cfd49 100644 --- a/src/main/java/election_structure/Voter.java +++ b/src/main/java/election_structure/Voter.java @@ -40,14 +40,6 @@ protected void setup() { this.registerDF(this, myVotingType.toString(), myVotingType.toString()); - if ( !randomAgentMalfunction || rand.nextInt(11) != 10 ) { - logger.log(Level.INFO, String.format("I'm the %s!", getLocalName())); - } else { - brokenAgent = true; - logger.log(Level.WARNING, - String.format("%s I'm agent %s and I have a malfunction! %s", ANSI_CYAN, getLocalName(), ANSI_RESET)); - } - if ( rand.nextInt(11) <= 5 ) { logger.log(Level.INFO, String.format("I'm the %s!", getLocalName())); } else {