/**
 * To debug the player
 *
 * @author Leo Nobach <*****@*****.**>
 * @version 05/06/2011
 */
public class ConsolePlayerNotifier implements PlayerEventListener {
  private static Logger log = SimLogger.getLogger(PlayerEventListener.class);

  @Override
  public void forward() {
    log.debug("PLAYER: Forward");
  }

  @Override
  public void pause() {
    log.debug("PLAYER: Pause");
  }

  @Override
  public void play() {
    log.debug("PLAYER: Play");
  }

  @Override
  public void reverse() {
    log.debug("PLAYER: Reverse");
  }

  @Override
  public void stop() {
    log.debug("PLAYER: Stop");
  }

  @Override
  public void speedChange(double speed) {
    log.debug("Speed Change: " + speed + "ms");
  }

  @Override
  public void quantizationChange(double quantization) {
    log.debug("Quantization Change: " + quantization + "ms");
  }
}
/**
 * This class manages the mapping of the 2-digits country code to country and region used in the
 * aggregated PingEr reports.
 *
 * @author Gerald Klunker <*****@*****.**>
 * @version 0.1, 09.01.2008
 */
public class CountryLookup implements Serializable {

  private static final long serialVersionUID = -3994762133062677848L;

  private static Logger log = SimLogger.getLogger(CountryLookup.class);

  private LinkedHashMap<String, String[]> countryLookup = new LinkedHashMap<String, String[]>();

  private LinkedHashMap<String, String> pingErCountryRegions = new LinkedHashMap<String, String>();

  private String pingErCountryRegionFilename;

  // sorted list holding PingEr Data for using in a graphical frontend only
  private ArrayList<String> pingErCountry = new ArrayList<String>();

  private ArrayList<String> pingErRegion = new ArrayList<String>();

  /**
   * @param 2-digits country code
   * @return dedicated GeoIP country name
   */
  public String getGeoIpCountryName(String countryCode) {
    if (countryLookup.containsKey(countryCode)) {
      return countryLookup.get(countryCode)[0];
    } else {
      return null;
    }
  }

  /**
   * @param 2-digits country code
   * @return dedicated PingEr country name
   */
  public String getPingErCountryName(String countryCode) {
    if (countryLookup.containsKey(countryCode)) {
      return countryLookup.get(countryCode)[1];
    } else {
      return null;
    }
  }

  /**
   * @param country 2-digits country code or pingEr country name
   * @return dedicated PingEr region name
   */
  public String getPingErRegionName(String country) {
    if (countryLookup.containsKey(country)) {
      return countryLookup.get(country)[2];
    } else if (pingErCountryRegions.containsKey(country)) {
      return pingErCountryRegions.get(country);
    }
    return null;
  }

  /**
   * Adds GeoIP country code and country name.
   *
   * <p>It will be assign automatically to PingEr Countries, if there are obvious consenses.
   *
   * @param 2-digits country code
   * @param dedicated country name from GeoIP
   */
  public void addCountryFromGeoIP(String countryCode, String country) {
    if (!countryLookup.containsKey(countryCode)) {
      String[] names = new String[3];
      names[0] = country;
      if (pingErCountryRegions.containsKey(country)) {
        names[1] = country;
        names[2] = pingErCountryRegions.get(country);
      }
      countryLookup.put(countryCode, names);
    }
  }

  /**
   * Assign a country code (from GeoIP) to PingER country and/or region name. Attention: Nothing
   * happens, if country code was not added before
   *
   * @param 2-digits country code
   * @param dedicated country name from PingER
   * @param dedicated region name from PingER
   */
  public void assignCountryCodeToPingErData(String code, String country, String region) {
    if (countryLookup.containsKey(code)) {
      String[] names = countryLookup.get(code);
      names[1] = country;
      names[2] = region;
    }
  }

  /**
   * Import all country and region names, that are used by the PingER Project. The Country - Region
   * Mapping File can be downloaded form the website of the project.
   * (http://www-iepm.slac.stanford.edu/pinger/region_country.txt)
   *
   * <p>GeoIP countries will be assign automatically to PingEr Countries, if there are obviouse
   * consensuses.
   *
   * @param file
   */
  public void importPingErCountryRegionFile(File file) {
    try {
      log.debug("Importing PingER-Country-Region-File: " + file.getAbsolutePath());
      FileReader inputFilePingER = new FileReader(file);
      BufferedReader inputPingER = new BufferedReader(inputFilePingER);
      LinkedHashMap<String, String> countryToRegion = new LinkedHashMap<String, String>();
      String line = inputPingER.readLine();
      while (line != null) {
        String[] parts = line.split(",");
        countryToRegion.put(parts[0], parts[1]);
        line = inputPingER.readLine();
      }
      inputPingER.close();
      inputFilePingER.close();

      Set<String> codes = countryLookup.keySet();
      for (String cc : codes) {
        String geoIpCountry = getGeoIpCountryName(cc);
        if (geoIpCountry != null && countryToRegion.containsKey(geoIpCountry)) {
          assignCountryCodeToPingErData(cc, geoIpCountry, countryToRegion.get(geoIpCountry));
        }
      }
      pingErCountryRegions.putAll(countryToRegion);
      this.pingErCountryRegionFilename = file.getAbsolutePath();

    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  /**
   * Import lockup data from an xml-element.
   *
   * @param element
   */
  public void importFromXML(Element element) {
    Iterator<Element> iter = element.elementIterator("CountryKey");
    while (iter.hasNext()) {
      Element variable = iter.next();
      String code = variable.attributeValue("code");
      String[] names = new String[3];
      names[0] = variable.attributeValue("countryGeoIP");
      names[1] = variable.attributeValue("countryPingEr");
      names[2] = variable.attributeValue("regionPingEr");
      countryLookup.put(code, names);
      pingErCountryRegions.put(names[1], names[2]);
    }
  }

  /**
   * Import lockup data from an xml-file.
   *
   * @param file
   */
  public void importFromXML(File file) {
    try {
      SAXReader reader = new SAXReader(false);
      Document configuration = reader.read(file);
      Element root = configuration.getRootElement();
      importFromXML(root);
    } catch (DocumentException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

  /** @return xml-element containing current lookup data */
  public Element exportToXML() {
    DefaultElement country = new DefaultElement("CountryLookup");
    Set<String> codeKeys = countryLookup.keySet();
    for (String code : codeKeys) {
      DefaultElement countryXml = new DefaultElement("CountryKey");
      countryXml.addAttribute("code", code);
      countryXml.addAttribute("countryGeoIP", getGeoIpCountryName(code));
      countryXml.addAttribute("countryPingEr", getPingErCountryName(code));
      countryXml.addAttribute("regionPingEr", getPingErRegionName(code));
      country.add(countryXml);
    }
    return country;
  }

  /** @return set of all available country codes added */
  public Set<String> getCountryCodes() {
    return countryLookup.keySet();
  }

  /** @return sorted list of all available PingEr country names */
  public ArrayList<String> getPingErCountrys() {
    if (pingErCountry.size() <= 1) {
      pingErCountry.clear();
      pingErCountry.addAll(pingErCountryRegions.keySet());
      pingErCountry.add("");
      Collections.sort(pingErCountry);
    }
    return pingErCountry;
  }

  /** @return sorted list of all available PingEr region names */
  public ArrayList<String> getPingErRegions() {
    if (pingErRegion.size() <= 1) {
      pingErRegion.clear();
      Set<String> region = new LinkedHashSet<String>();
      region.addAll(pingErCountryRegions.values());
      pingErRegion.addAll(region);
      pingErRegion.add("");
      Collections.sort(pingErRegion);
    }
    return pingErRegion;
  }

  /**
   * Remove all countries that are not defined in the Set
   *
   * @param countryCodes Set of country codes
   */
  public void keepCountries(Set<String> countryCodes) {
    countryLookup.keySet().retainAll(countryCodes);
  }

  /**
   * @param name of country or region
   * @return true, if there is a country or region with name exist
   */
  public boolean containsPingErCountryOrRegion(String name) {
    for (String[] names : countryLookup.values()) {
      if (names[1] != null && names[1].equals(name)) {
        return true;
      }
      if (names[2] != null && names[2].equals(name)) {
        return true;
      }
    }
    return false;
  }

  /** @return PingER Country - Region Mapping Filename (region_country.txt) used for naming */
  public String getPingErCountryRegionFilename() {
    return pingErCountryRegionFilename;
  }
}
Пример #3
0
/**
 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! This part of the
 * Simulator is not maintained in the current version of PeerfactSim.KOM. There is no intention of
 * the authors to fix this circumstances, since the changes needed are huge compared to overall
 * benefit.
 *
 * <p>If you want it to work correctly, you are free to make the specific changes and provide it to
 * the community. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!
 *
 * <p>This class implements the calculation of the position of a SkyNet-node in the SkyNet-tree and
 * retrieves the information of the determined Parent-Coordinator.
 *
 * @author Dominik Stingl <*****@*****.**>
 * @version 1.0, 04.12.2008
 */
public class TreeHandler {

  private static Logger log = SimLogger.getLogger(TreeHandler.class);

  private boolean isRoot;

  private SkyNetNodeInfo parentCoordinator;

  private final SkyNetNodeInterface skyNetNode;

  private SkyNetID coordinatorKey;

  private int level;

  private final int branchingFactor;

  private final TreeHandlerDelegator treeHandlerDelegator;

  public TreeHandler(SkyNetNodeInterface node, TreeHandlerDelegator treeHandlerDelegator) {
    branchingFactor =
        SkyNetPropertiesReader.getInstance().getIntProperty("SkyNetTreeBranchingFactor");

    this.skyNetNode = node;
    this.treeHandlerDelegator = treeHandlerDelegator;
    this.treeHandlerDelegator.setSkyNetNode(skyNetNode);
    this.treeHandlerDelegator.setOwnOverlayNode(skyNetNode.getOverlayNode());
    isRoot = false;
    parentCoordinator = new SkyNetNodeInfoImpl(null, null, null, -1);
    coordinatorKey = null;
    level = 0;
  }

  /**
   * This method puts <code>TreeHandler</code> back in its initial state, if the host got off-line
   * or if the peer left the underlying overlay.
   */
  public void reset() {
    isRoot = false;
  }

  /**
   * This method tests, if a SkyNet-node is currently the root of the SkyNet-tree.
   *
   * @return <code>true</code>, if the node is the root, <code>false</code> otherwise
   */
  public boolean isRoot() {
    return isRoot;
  }

  public void verticalDispatching() {
    // for later versions
  }

  public void horizontalDispatching() {
    // for later versions
  }

  /**
   * This method returns the information of the current Parent-Coordinator, which is required to
   * address the Parent-Coordinator.
   *
   * @return the <code>SkyNetNodeInfo</code> of the ParentCoordinator
   */
  public SkyNetNodeInfo getParentCoordinator() {
    if (parentCoordinator != null) {
      if (parentCoordinator.isComplete()) {
        return parentCoordinator.clone();
      } else {
        return null;
      }
    } else {
      return null;
    }
  }

  // ----------------------------------------------------------------------
  // methods for traveling down the tree
  // ----------------------------------------------------------------------

  private void checkResponsibility(
      SkyNetID ownID, SkyNetID skyNetCoKey, BigDecimal left, BigDecimal right, int iter) {
    skyNetNode.getSkyNetNodeInfo().setCoordinatorKey(skyNetCoKey);
    log.info(
        " The client "
            + skyNetNode.getSkyNetNodeInfo().toString()
            + " is responsible for the CoordinatorKey "
            + skyNetCoKey.getPlainSkyNetID()
            + " in the interval["
            + left.toPlainString()
            + ";"
            + right.toPlainString()
            + "] @ level "
            + iter);

    ISkyNetMonitor monitor = (ISkyNetMonitor) Simulator.getMonitor();
    ChurnStatisticsAnalyzer csAnalyzer =
        (ChurnStatisticsAnalyzer) monitor.getConnectivityAnalyzer(ChurnStatisticsAnalyzer.class);

    if (iter > 0) {
      // complete the parentSkyNetNode Info
      if (isRoot) {
        log.warn(SkyNetUtilities.getTimeAndNetID(skyNetNode) + "lost the root-position");
        csAnalyzer.lostRootPosition(skyNetNode);
        skyNetNode.getMetricUpdateStrategy().setLastMetricSync(0);
      }
      skyNetNode.getSkyNetNodeInfo().setLevel(iter);
      isRoot = false;
      lookupParentCoordinator();
    } else {
      if (!isRoot) {
        log.warn(SkyNetUtilities.getTimeAndNetID(skyNetNode) + "got the root-position");
        csAnalyzer.gotRootPosition(skyNetNode);
        skyNetNode.getMetricUpdateStrategy().setLastMetricSync(0);
      }
      skyNetNode.getSkyNetNodeInfo().setLevel(iter);

      // Also set the observed level at this point
      skyNetNode.getSkyNetNodeInfo().setObservedLevelFromRoot(0);

      isRoot = true;
      skyNetNode.getAttributeUpdateStrategy().resetOnlyAttributeUpdateStrategy();
      skyNetNode.getMetricUpdateStrategy().sendNextDataUpdate();
    }
  }

  private void calculateNextLevel(
      SkyNetID ownID, SkyNetID skyNetCoKey, BigDecimal left, BigDecimal right, int iter) {
    if (iter == 0) {
      coordinatorKey = skyNetCoKey;
      level = iter;
    } else {
      coordinatorKey = skyNetCoKey;
      level = iter;
    }
    if (iter < 100) {
      // call processNextLevel(...), but before split the interval
      // defined by left and right in k subintervals as defined by
      // branchingFactor.
      BigDecimal interval = right.subtract(left);
      BigDecimal intervalStep = interval.divide(new BigDecimal(String.valueOf(branchingFactor)));
      BigDecimal tempLeft = left;
      BigDecimal tempRight = left.add(new BigDecimal(String.valueOf(intervalStep)));
      log.info(
          SkyNetUtilities.getTimeAndNetID(skyNetNode)
              + "is actually in the interval between "
              + left.toPlainString()
              + " and "
              + right.toPlainString()
              + ". The size of the interval is"
              + interval);
      int correctnessCounter = 0;
      while (ownID.getID().compareTo(tempRight) > -1) {
        tempLeft = tempRight;
        tempRight = tempRight.add(new BigDecimal(String.valueOf(intervalStep)));
        if (correctnessCounter < branchingFactor) {
          correctnessCounter++;
        } else {
          log.fatal(
              "There are actually "
                  + (correctnessCounter + 1)
                  + " intervals instead of "
                  + branchingFactor);
        }
      }
      processNextLevel(ownID, tempLeft, tempRight, iter + 1);

    } else {
      skyNetNode.getMetricUpdateStrategy().scheduleNextUpdateEvent();
      parentCoordinator = null;
      if (isRoot) {
        log.warn(SkyNetUtilities.getTimeAndNetID(skyNetNode) + "lost the root-position");
      }
      isRoot = false;
      log.error(
          SkyNetUtilities.getTimeAndNetID(skyNetNode)
              + "is to deep in the tree."
              + "Probably no predecessor in the overlay can be found"
              + " to calculate the 'isRootOf'-method");
    }
  }

  // ----------------------------------------------------------------------
  // methods for checking the responsibility-interval on different overlays
  // ----------------------------------------------------------------------

  /**
   * If it is possible to calculate the responsibility interval of a peer on the current overlay,
   * this method calculates the corresponding responsibility interval of the node in the ID-space of
   * SkyNet. In this context, the responsibility interval is used to test, if a SkyNet-node is
   * responsible for a Coordinator.
   *
   * @param id contains the ID of this SkyNet-node
   */
  public void calculateResponsibilityInterval(SkyNetID id) {
    if (((AbstractOverlayNode<?, ?>) skyNetNode.getOverlayNode())
        .getPeerStatus()
        .equals(PeerStatus.PRESENT)) {
      // execute getPredecessor-method
      final SkyNetID ownID = id;
      treeHandlerDelegator.calculateResponsibilityInterval(
          ownID,
          new OperationCallback<OverlayContact<OverlayID<?>>>() {

            @Override
            public void calledOperationFailed(Operation<OverlayContact<OverlayID<?>>> op) {
              calculateResponsibilityIntervalOperationFailed(op);
            }

            @Override
            public void calledOperationSucceeded(Operation<OverlayContact<OverlayID<?>>> op) {
              calculateResponsibilityIntervalOperationSucceeded(op, ownID);
            }
          });
    } else {
      log.warn("SkyNetNode cannot get Predecessor" + ", because he is not PRESENT");
    }
  }

  void calculateResponsibilityIntervalOperationFailed(Operation<OverlayContact<OverlayID<?>>> op) {
    treeHandlerDelegator.calculateResponsibilityIntervalOperationFailed(op);
    skyNetNode.getMetricUpdateStrategy().scheduleNextUpdateEvent();
  }

  void calculateResponsibilityIntervalOperationSucceeded(
      Operation<OverlayContact<OverlayID<?>>> op, SkyNetID ownID) {
    treeHandlerDelegator.calculateResponsibilityIntervalOperationSucceeded(op);
    int iter = 0;
    BigDecimal left = new BigDecimal(0);
    BigDecimal right = new BigDecimal(1);
    level = 0;
    processNextLevel(ownID, left, right, iter);
  }

  // ----------------------------------------------------------------------
  // methods for traveling down the tree
  // ----------------------------------------------------------------------

  /**
   * This method is responsible for the calculation of the position of the SkyNet-node in the
   * SkyNet-tree. Additionally, it determines the key of the Parent-Coordinator, which can be looked
   * up.<br>
   * This method starts the recursive calculation, where first the determination of the Coordinator
   * for every new interval is executed. Then it is checked, if the SkyNet-node is responsible for
   * that Coordinator. In case of a positive outcome, the Parent-Coordinator is looked up,
   * otherwise, the interval at the next level is calculated, to which the SkyNet-node must descend.
   *
   * @param ownID the ID of this SkyNet-node
   * @param left the left bound of the interval
   * @param right the right bound of the interval
   * @param iter the current level
   */
  private void processNextLevel(SkyNetID ownID, BigDecimal left, BigDecimal right, int iter) {

    BigDecimal temp = left.add(right);
    temp = temp.divide(new BigDecimal(String.valueOf(2)));
    // BigDecimal temp = new BigDecimal((left + right) / 2);
    SkyNetID skyNetCoKey = new SkyNetID(temp);

    // call the process-method for the corresponding overlay
    treeHandlerDelegator.processNextLevel(
        ownID,
        skyNetCoKey,
        left,
        right,
        iter,
        new OperationCallback<Object>() {

          @Override
          public void calledOperationFailed(Operation<Object> op) {
            processNextLevelOperationFailed(op);
          }

          @Override
          public void calledOperationSucceeded(Operation<Object> op) {
            processNextLevelOperationSucceeded(op);
          }
        });
  }

  void processNextLevelOperationFailed(Operation<?> op) {
    treeHandlerDelegator.processNextLevelOperationFailed(op);
    skyNetNode.getMetricUpdateStrategy().scheduleNextUpdateEvent();
  }

  void processNextLevelOperationSucceeded(Operation<?> op) {
    ProcessNextLevelResult result = treeHandlerDelegator.processNextLevelOperationSucceeded(op);
    if (result.isKeyResponsibility()) {
      checkResponsibility(
          result.getOwnID(),
          result.getSkyNetCoKey(),
          result.getLeft(),
          result.getRight(),
          result.getIter());
    } else {
      calculateNextLevel(
          result.getOwnID(),
          result.getSkyNetCoKey(),
          result.getLeft(),
          result.getRight(),
          result.getIter());
    }
  }

  // ----------------------------------------------------------------------
  // methods for looking up the needed additional information of the
  // ParentCoordinator on different overlays
  // ----------------------------------------------------------------------

  private void lookupParentCoordinator() {
    if (((AbstractOverlayNode<?, ?>) skyNetNode.getOverlayNode())
        .getPeerStatus()
        .equals(PeerStatus.PRESENT)) {
      log.debug(
          SkyNetUtilities.getTimeAndNetID(skyNetNode)
              + "starts a lookup for the key "
              + coordinatorKey.getPlainSkyNetID());
      treeHandlerDelegator.lookupParentCoordinator(
          coordinatorKey,
          new OperationCallback<OverlayContact<OverlayID<?>>>() {

            @Override
            public void calledOperationFailed(Operation<OverlayContact<OverlayID<?>>> op) {
              lookupOperationFailed(op);
            }

            @Override
            public void calledOperationSucceeded(Operation<OverlayContact<OverlayID<?>>> op) {
              lookupOperationSucceeded(op);
            }
          });
    } else {
      log.warn("SkyNetNode cannot lookup ParentCoordinator" + ", because he is not PRESENT");
    }
  }

  void lookupOperationFailed(Operation<OverlayContact<OverlayID<?>>> op) {
    treeHandlerDelegator.lookupOperationFailed(op);
    skyNetNode.getMetricUpdateStrategy().scheduleNextUpdateEvent();
  }

  void lookupOperationSucceeded(Operation<OverlayContact<OverlayID<?>>> op) {
    LookupResult result = treeHandlerDelegator.lookupOperationSucceeded(op);
    parentCoordinator =
        new SkyNetNodeInfoImpl(
            result.getSkyNetID(),
            coordinatorKey,
            DefaultTransInfo.getTransInfo(
                result.getContact().getTransInfo().getNetId(), skyNetNode.getPort()),
            level);
    log.info(
        parentCoordinator.toString()
            + " is parentCoordinator of "
            + skyNetNode.getSkyNetNodeInfo().toString());

    skyNetNode.getMetricUpdateStrategy().sendNextDataUpdate();
  }
}