/** * This software is GPLv2. * Take a look at the LICENSE file for more info. */ package de.tu.dresden.dud.dc; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Observable; import de.tu.dresden.dud.dc.WorkCycle.WorkCycle; /** * A ParticipantManager keeps track of different {@link Participant}s that are * known to the {@link Server} or the {@link Participant}s. * * Each server has one associated participant manager. Each participant has one * associated participant manger per connection. * * This class is an observable. It notifies the observers after changes happen * to the tracked participants. * * @author klobs * */ public class ParticipantManager extends Observable{ /** * */ private static final long serialVersionUID = -2335675816206621702L; // this is for graphical output... :( /** * Notification for observers. A new participant has been added for tracking. */ public static final int PARTMNG_INTERVAL_ADDED_GENERAL = 0; /** * Notification for observers. A new participant has been added and it * directly became active. */ public static final int PARTMNG_INTERVAL_ADDED_ACTIVE = 1; /** * Notification for observers. A new participant has been added and it * directly became passive. */ public static final int PARTMNG_INTERVAL_ADDED_PASSIVE = 2; /** * Notification for observers. A new participant has beend added and it * directly became active. */ public static final int PARTMNG_INTERVAL_CHANGED_ACTIVE = 3; /** * Notification for observers. A new participant has beend added and it * directly became passive. */ public static final int PARTMNG_INTERVAL_CHANGED_PASSIVE = 4; private List<ParticipantMgmntInfo> participantDB = Collections.synchronizedList(new LinkedList<ParticipantMgmntInfo>()); private Participant me = null; /** * Each {@link Participant} of the linked list will be added for tracking. * * Actually only calls addParticipant() for each element of pl. * * @param pl list of participants that shall be added for tracking. */ public void addParticipants(LinkedList<Participant> pl){ for (Participant p : pl){ addParticipant(p); } } /** * Adds a participant for tracking. * It also creates the corresponding {@link ParticipantMgmntInfo} for the new participant. * @param p {@link Participant} that you want to add for tracking. * @return {@link ParticipantMgmntInfo} that has been created for p. */ public ParticipantMgmntInfo addParticipant(Participant p){ ParticipantMgmntInfo pmi = getParticipantMgmntInfoFor(p); if (pmi == null){ pmi = new ParticipantMgmntInfo(p); // this is the model stuff. // As we do it for each participant individually, it can become quite slow, i guess // for a big number of participants. participantDB.add(pmi); setChanged(); notifyObservers(PARTMNG_INTERVAL_ADDED_GENERAL); } return pmi; } /** * Returns a list with all known {@link Participant}'s * {@link ParticipantMgmntInfo} that are active. * * @return The list with active participants. */ public synchronized LinkedList<ParticipantMgmntInfo> getActivePartMgmtInfo(){ Iterator<ParticipantMgmntInfo> i = participantDB.iterator(); LinkedList<ParticipantMgmntInfo> l = new LinkedList<ParticipantMgmntInfo>(); ParticipantMgmntInfo pmi = null; while(i.hasNext()){ pmi = i.next(); if (pmi.isActive()) l.add(pmi); } return l; } public synchronized void cleanAllButPassiveConnections(LinkedList<Participant> ppl){ HashSet<ParticipantMgmntInfo> oldPpl = new HashSet<ParticipantMgmntInfo>(); oldPpl.addAll(getPassivePartMgmtInfo()); oldPpl.removeAll(ppl); participantDB.removeAll(oldPpl); setChanged(); notifyObservers(PARTMNG_INTERVAL_CHANGED_PASSIVE); } public synchronized LinkedList<ParticipantMgmntInfo> getActivePartExtKeysMgmtInfo(){ Iterator<ParticipantMgmntInfo> i = participantDB.iterator(); LinkedList<ParticipantMgmntInfo> l = new LinkedList<ParticipantMgmntInfo>(); ParticipantMgmntInfo pmi = null; while(i.hasNext()){ pmi = i.next(); if (pmi.isActive() && pmi.hasExchangedKey()) l.add(pmi); } return l; } /** * Direct access to the database of tracked participants * @param i which element of the database you want to return * @return the corresponding {@link ParticipantMgmntInfo} */ public synchronized ParticipantMgmntInfo getElementAt(int i){ return participantDB.get(i); } /** * Standard getter. * * @return The {@link Participant} which is the owner of the * {@link ParticipantManager}. */ public synchronized Participant getMe(){ return me; } public synchronized ParticipantMgmntInfo getMyInfo(){ return getParticipantMgmntInfoFor(me); } /** * Standard getter. * * @param p * an already tracked participant. Can be null, but then the * result will also be null. * @return the ManagementInformation for the specific participant p. Returns * null, if p is null, or does not exist. */ public synchronized ParticipantMgmntInfo getParticipantMgmntInfoFor(Participant p){ if (p == null) return null; Iterator<ParticipantMgmntInfo> i = participantDB.iterator(); ParticipantMgmntInfo pm = null; while(i.hasNext()){ pm = i.next(); if (pm.getParticipant().equalsTo(p)) return pm; } return null; } /** * Standard getter. * * @param c * a connection that belongs to a participant. Can be null, but then the * result will also be null. * @return the ManagementInformation for the specific participant p. Returns * null, if p is null, or does not exist. */ public synchronized ParticipantMgmntInfo getParticipantMgmntInfoFor(Connection c){ if (c == null) return null; Iterator<ParticipantMgmntInfo> i = participantDB.iterator(); ParticipantMgmntInfo pm = null; while(i.hasNext()){ pm = i.next(); if (pm.getAssocConnection().equals(c)) return pm; } return null; } /** * Standard getter. * * @param id * An id of a participant * @return the ManagementInformation that belongs to the {@link Participant} * with the id. */ public synchronized ParticipantMgmntInfo getParticipantMgmntInfoByParticipantID(String id){ if (id == null) return null; Iterator<ParticipantMgmntInfo> i = participantDB.iterator(); ParticipantMgmntInfo pm = null; while(i.hasNext()){ pm = i.next(); if (pm.getParticipant().getId().compareTo(id) == 0) return pm; } return null; } /** * Returns a list with all known {@link Participant}'s * {@link ParticipantMgmntInfo} that are passive. These include all acvite * participants, too. * * @return The list with active participants. */ public synchronized LinkedList<ParticipantMgmntInfo> getPassivePartMgmtInfo(){ Iterator<ParticipantMgmntInfo> i = participantDB.iterator(); LinkedList<ParticipantMgmntInfo> l = new LinkedList<ParticipantMgmntInfo>(); ParticipantMgmntInfo pmi = null; while(i.hasNext()){ pmi = i.next(); if (pmi.isPassive()) l.add(pmi); } return l; } /** * Standard getter. * @return The number of tracked participants. */ public synchronized int getSize() { return participantDB.size(); } public synchronized void removeParticipant(ParticipantMgmntInfo pmi){ if (participantDB.contains(pmi)){ participantDB.remove(pmi); } } public synchronized void removeParticipant(Participant p){ ParticipantMgmntInfo pmi = getParticipantMgmntInfoFor(p); if (pmi != null){ participantDB.remove(pmi); } } /** * Standard setter. * * Associate a {@link Participant} with the {@link ParticipantManager}. * @param p The participant that you want to associate to the participant manager. */ public synchronized void setMe(Participant p){ me = p; } /** * Find {@link Participant} p in the database, and set it to an active * state. If p is not yet member of the database, create p. * * This method notifies the observers, as described in the general * description of this class. * * @param p */ public synchronized void setParticipantActive(Participant p){ if(p == null) return; ParticipantMgmntInfo t = getParticipantMgmntInfoFor(p); if(t == null) t = addParticipant(p); t.setActive(); setChanged(); notifyObservers(PARTMNG_INTERVAL_CHANGED_ACTIVE); } /** * This method marks a participant to become active in {@link WorkCycle} with work cycle number r. * @param p Participant that shall be modified. * @param r work cycle number on which p becomes active. */ public synchronized void setParticipantActiveAfterWorkCycle(Participant p, long r){ if(p == null) return; ParticipantMgmntInfo t = getParticipantMgmntInfoFor(p); if(t == null) t = addParticipant(p); t.setActiveInWorkCycle(r); } /** * Take each {@link Participant} in p and call setParticipantActive(). * @param pl A list of participants that shall be set to be active. */ public synchronized void setParticipantsActive(LinkedList<Participant> pl){ for(Participant p : pl) setParticipantActive(p); } /** * Find {@link Participant} p in the database, and set it to an passive * state. If p is not yet member of the database, create p. * * This method notifies the observers, as described in the general * description of this class. * * @param p */ public synchronized void setParticipantPassive(Participant p){ ParticipantMgmntInfo t = getParticipantMgmntInfoFor(p); if(p == null) return; if(t == null) t = addParticipant(p); t.setPassive(true); setChanged(); notifyObservers(PARTMNG_INTERVAL_CHANGED_PASSIVE); } /** * Take each {@link Participant} in p and call setParticipantPassive(). * @param pl A list of participants that shall be set to be passive. */ public synchronized void setParticipantsPassive(LinkedList<Participant> pl){ for(Participant p : pl) setParticipantPassive(p); } /** * Set the active record for participant p to false. * * @param p Participant that you want to set inactive. Remark: p stays passive. */ public synchronized void unsetParticipantActive(Participant p){ if(p == null) return; ParticipantMgmntInfo t = getParticipantMgmntInfoFor(p); if(t == null) t = addParticipant(p); t.setInactive(); setChanged(); notifyObservers(PARTMNG_INTERVAL_CHANGED_ACTIVE); } /** * Take each {@link Participant} in p and call unsetParticipantActive(). * @param pl A list of participants that shall be set to be inactive. */ public synchronized void unsetParticipantsActive(LinkedList<Participant> pl){ for(Participant p : pl) unsetParticipantActive(p); } /** * This method marks a participant to become inactive in {@link WorkCycle} with work cycle number r. * @param p Participant that shall be modified. * @param r work cycle number on which p becomes active. */ public synchronized void unsetParticipantActiveAfterWorkCycle(Participant p, long r){ if(p == null) return; ParticipantMgmntInfo t = getParticipantMgmntInfoFor(p); if(t == null) t = addParticipant(p); t.setInactiveInWorkCycle(r); } /** * Set the passive record for participant p to false. * * @param p Participant that you want to set inpassive. */ public synchronized void unsetParticipantPassive(Participant p){ ParticipantMgmntInfo t = getParticipantMgmntInfoFor(p); if(p == null) return; if(t == null) t = addParticipant(p); t.setPassive(false); setChanged(); notifyObservers(PARTMNG_INTERVAL_CHANGED_PASSIVE); } /** * Take each {@link Participant} in p and call unsetParticipantPassive(). * @param pl A list of participants that shall be set to be inpassive. */ public synchronized void unsetParticipantsPassive(LinkedList<Participant> pl){ for(Participant p : pl) unsetParticipantPassive(p); } /** * After a new work cycle begins, this method shall be called with the new work cycle * number. It then sets all participants to active whose 'become active * in'-work cycle number is smaller or equal work cycle number. * * Usually this method is called from {@link WorkCycle}, performWorkCycleOnServerSide(). * * @param workcyclenumber */ public synchronized void update(long workcyclenumber){ Iterator<ParticipantMgmntInfo> i = participantDB.iterator(); ParticipantMgmntInfo pmi = null; while(i.hasNext()){ pmi = i.next(); if(pmi.getActiveInWorkCycle() > -1 && pmi.getActiveInWorkCycle() <= workcyclenumber) pmi.setActive(); if(pmi.getInactiveInWorkCycle() > -1 && pmi.getInactiveInWorkCycle() <= workcyclenumber) pmi.setInactive(); } } }