Package com.alu.e3.topology

Source Code of com.alu.e3.topology.TopologyWatcher

/**
* Copyright © 2012 Alcatel-Lucent.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* Licensed to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*          http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.alu.e3.topology;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alu.e3.common.E3Constant;
import com.alu.e3.common.osgi.api.IHealthCheckFactory;
import com.alu.e3.common.osgi.api.ITopologyClient;
import com.alu.e3.data.IHealthCheckService;
import com.alu.e3.data.model.Instance;
import com.alu.e3.data.topology.IInstanceListener;
import com.alu.e3.data.topology.InstanceEvent;

/**
* Keeps track of the topology using health check mechanism and update the TopologyClient accordingly.
*/
public class TopologyWatcher implements Runnable, IInstanceListener {
 
  private static final Logger logger = LoggerFactory.getLogger(TopologyWatcher.class);
 
  private ITopologyClient topologyClient;
  private IHealthCheckFactory healthCheckFactory;
   
  private List<Instance> upGateways = new ArrayList<Instance>();
  private List<Instance> upGatewaysActive = new ArrayList<Instance>();
  private List<Instance> downGateways = new ArrayList<Instance>();

  private List<Instance> upSpeakers = new ArrayList<Instance>();
  private List<Instance> upSpeakersActive = new ArrayList<Instance>();
  private List<Instance> downSpeakers = new ArrayList<Instance>();
 
  private int pollingInterval = E3Constant.HEALTH_CHECK_POLLING_INTERVAL;
 
  private volatile boolean running;

  private Thread localThread;
 
  public TopologyWatcher() {}
 
  /**
   * Sets the polling interval.
   */
  public void setPollingInterval(int pollingInterval) {
    this.pollingInterval = pollingInterval;
  }
 
  /**
   * Sets the healthCheckFactory object
   */
  public void setHealthCheckFactory(IHealthCheckFactory healthCheckFactory) {
    this.healthCheckFactory = healthCheckFactory;
  }
 
  /**
   * Set the topologyClient object
   */ 
  public void setTopologyClient(ITopologyClient topologyClient) {
    this.topologyClient = topologyClient;
  }
 
  /**
   * Starts watching of the nodes
   */
  public void init() {
    topologyClient.addInstanceListener(this);
   
    // get the list of gateways + speaker to monitor
    List<Instance> nodeList;

    synchronized (this) {
      nodeList = topologyClient.getAllInstancesOfType(E3Constant.E3GATEWAY);
      if (nodeList != null) {
        upGateways.addAll(nodeList);
      }
     
      nodeList = topologyClient.getAllInstancesOfType(E3Constant.E3GATEWAY_ACTIVE);
      if (nodeList != null) {
        upGatewaysActive.addAll(nodeList);
      }
     
      nodeList = topologyClient.getAllInstancesOfType(E3Constant.E3SPEAKER);
      if (nodeList != null) {
        upSpeakers.addAll(nodeList);
      }
     
      nodeList = topologyClient.getAllInstancesOfType(E3Constant.E3SPEAKER_ACTIVE);
      if (nodeList != null) {
        upSpeakersActive.addAll(nodeList);
      }
     
    }
   
    // start the watching of nodes
    setRunning(true);
   
    // TODO what is doing the passive manager? watching only the active manager? how do we know active or passive?   
    localThread = new Thread(this);
    localThread.start();
  }
 
  /**
   * Stops watching the nodes
   */
  public void destroy() {
    if(logger.isDebugEnabled()) {
      logger.debug("Stopping TopologyWatcher ...");
    }
    setRunning(false);

    if(logger.isDebugEnabled()) {
      logger.debug("Clearing TopologyWatcher list ...");
    }
    synchronized (this) {
      upGateways.clear();
      upGatewaysActive.clear();
      upSpeakers.clear();
      upSpeakersActive.clear();
    }

    if(logger.isDebugEnabled()) {
      logger.debug("Clearing TopologyWatcher listeners ...");
    }
    topologyClient.removeInstanceListener(this);

    if(logger.isDebugEnabled()) {
      logger.debug("TopologyWatcher waiting for its local thread (join) ...");
    }
    try {
      localThread.join();
    } catch (InterruptedException e) {
      logger.error("Unable to join TopologyWatcher local thread", e);
    }
    if(logger.isDebugEnabled()) {
      logger.debug("TopologyWatcher destroyed.");
    }
  }

  /**
   * Runnable implementation
   */
  @Override
  public void run() {
    do {
      try {
        synchronized (this) {
          // check the active gateways which are up
          // if an active gateways is down, it is removed from the list of E3GATEWAY_ACTIVE in the TopologyClient
          checkUpNodes(upGatewaysActive, null, E3Constant.E3GATEWAY_ACTIVE);
         
          // check the gateways which are up
          // if a gateway is down, it is removed from the list of E3GATEWAY in the TopologyClient
          checkUpNodes(upGateways, downGateways, E3Constant.E3GATEWAY);
         
          // check the active speakers which are up
          // if an active speaker is down, it is removed from the list of E3SPEAKER_ACTIVE in the TopologyClient
          checkUpNodes(upSpeakersActive, null, E3Constant.E3SPEAKER_ACTIVE);
         
          // check the speakers which are up
          // if a speaker is down, it is removed from the list of E3SPEAKER in the TopologyClient
          checkUpNodes(upSpeakers, downSpeakers, E3Constant.E3SPEAKER);
         
          // check the gateways which are down
          // if a gateway becomes up, it is added to the list of E3GATEWAY in the TopologyClient
          checkDownNodes(upGateways, downGateways, E3Constant.E3GATEWAY);
         
          // check the speakers which are down
          // if a speaker becomes up, it is added to the list of E3SPEAKER in the TopologyClient
          checkDownNodes(upSpeakers, downSpeakers, E3Constant.E3SPEAKER);
         
          // check the gateways that are becoming active
          // if a gateway becomes active, it is added to the list of E3GATEWAY_ACTIVE in the TopologyClient
          checkForActiveGateways();
         
          // check if there's a new speaker
          // if a speaker becomes active, it is added to the list of E3SPEAKER_ACTIVE in the TopologyClient
          checkForNewElectedSpeakers();
        }
        Thread.sleep(pollingInterval);
      } catch (InterruptedException e) {
        logger.warn("TopologyWatcher thread interrupted", e);
        running = false;
      }
    } while (running);
  }
 
  /**
   * Return the correct IP depending on the area
   */
  private String getIPWithArea(Instance node) {
    String myArea = topologyClient.getMyArea();
   
    if (myArea == null || myArea.equals(node.getArea())) {
      return node.getInternalIP();
    }
    else {
      return node.getExternalIP();
    }   
  }
 
  /**
   * Check if a gateway is becoming active
   */
  private void checkForActiveGateways() {
    Instance[] nodes = new Instance[0];
   
    synchronized (this) {
      nodes = upGateways.toArray(nodes);
    }
   
    for (int i = 0; i < nodes.length; i++) {
      Instance node = nodes[i];
     
      if (!upGatewaysActive.contains(node) && checkIfUp(getIPWithArea(node), E3Constant.E3GATEWAY_ACTIVE)) {
        logger.info("A gateway became active: {}", node);
       
        upGatewaysActive.add(node); // keep the node
        Instance newNode = new Instance(node);
        newNode.setType(E3Constant.E3GATEWAY_ACTIVE);
        topologyClient.addInstance(newNode);
      }
    }
  }
 
  /**
   * Check if a new speaker is up
   */
  private void checkForNewElectedSpeakers() {
    // iterate over the speakers and check if the Speaker heart beat is up
    Instance[] nodes = new Instance[0];
   
    nodes = upSpeakers.toArray(nodes);
   
    for (int i = 0; i < nodes.length; i++) {
      Instance node = nodes[i];
      if (!upSpeakersActive.contains(node) && checkIfUp(getIPWithArea(node), E3Constant.E3SPEAKER_ACTIVE)) {
        logger.info("A speaker became elected: {}", node);
       
        upSpeakersActive.add(node); // keep the node
        Instance newNode = new Instance(node);
        newNode.setType(E3Constant.E3SPEAKER_ACTIVE);
        topologyClient.addInstance(newNode);
      }
    }
  }
 
  /**
   * Check if the upNodes are still up
   */
  private void checkUpNodes(List<Instance> upNodes, List<Instance> downNodes, String type) {
    Instance[] nodes = new Instance[0];
   
    nodes = upNodes.toArray(nodes);
   
    for (int i = 0; i < nodes.length; i++) {
      Instance node = nodes[i];
      if (!checkIfUp(getIPWithArea(node), type)) {
        logger.info("A node became down: {}", node);
       
        upNodes.remove(node);
       
        if (downNodes != null) {
          downNodes.add(node);
        }
       
        Instance newNode = new Instance(node);
        newNode.setType(type);
        topologyClient.deleteInstance(newNode);
      }
    }
  }
 
  /**
   * Check if the downNodes are still down
   */
  private void checkDownNodes(List<Instance> upNodes, List<Instance> downNodes, String type) {
    Instance[] nodes = new Instance[0];
   
    nodes = downNodes.toArray(nodes);
   
    for (int i = 0; i < nodes.length; i++) {
      Instance node = nodes[i];
      if (checkIfUp(getIPWithArea(node), type)) {
        logger.info("A node became up: {}", node);

        downNodes.remove(node);
        upNodes.add(node);
       
        topologyClient.addInstance(node);
      }
    }
  }
 
  /**
   * Check if the node is up
   */
  private boolean checkIfUp(String node, String type) {
   
    if (healthCheckFactory == null) {
      logger.warn("No health check factory available for now");
      return false;
    }
   
    String instanceType;
   
    if (E3Constant.E3GATEWAY.equals(type)) {
      instanceType = IHealthCheckFactory.GATEWAY_INTERNAL_TYPE;
    }
    else if (E3Constant.E3SPEAKER.equals(type)) {
      // While SPEAKER feature does not exist without a GATEWAY
      // it hasn't its own INTERNAL_TYPE port
      // So, let's check a SPEAKER existence when a GATEWAY is Active (and provisioned)
      instanceType = IHealthCheckFactory.GATEWAY_TYPE;
    }
    else if (E3Constant.E3GATEWAY_ACTIVE.equals(type)) {
      instanceType = IHealthCheckFactory.GATEWAY_TYPE;
    }
    else if (E3Constant.E3SPEAKER_ACTIVE.equals(type)) {
      instanceType = IHealthCheckFactory.SPEAKER_TYPE;
    }
    else {
      logger.warn("Unknown type: {} while creating HealthCheckService", type);
      return false;
    }
   
    IHealthCheckService healthCheckService;
   
    healthCheckService = healthCheckFactory.getHealthCheckService(instanceType);
   
    return healthCheckService.check(node);
  }

  private boolean isAlreadyRegistered(Instance instance, List<Instance> list)
  {
    for (Instance i : list)
    {
      if (i.getName().equals(instance.getName()))
      {
        return true;
      }
    }
    return false;
  }
 
  /**
   * IInstanceListener implementation
   */
  @Override
  public synchronized void instanceAdded(InstanceEvent event) {
    if (E3Constant.E3GATEWAY.equals(event.getType())) {
      if (isAlreadyRegistered(event.getInstance(), downGateways) || isAlreadyRegistered(event.getInstance(), upGateways))
      {
        return;
      }
     
      upGateways.add(event.getInstance());
     
      if(logger.isDebugEnabled()) {
        logger.debug("E3GATEWAY added: {}", event.getInstance());
      }
    }
   
    else if (E3Constant.E3SPEAKER.equals(event.getType())) {
      if (isAlreadyRegistered(event.getInstance(), downSpeakers) || isAlreadyRegistered(event.getInstance(), upSpeakers))
      {
        return;
      }
     
      upSpeakers.add(event.getInstance());
     
      if(logger.isDebugEnabled()) {
        logger.debug("E3SPEAKER added: {}", event.getInstance());
      }
    }
   
    else if (E3Constant.E3GATEWAY_ACTIVE.equals(event.getType())) {
      if(logger.isDebugEnabled()) {
        logger.debug("E3GATEWAY_ACTIVE added: {}", event.getInstance());
      }
    }
    else if (E3Constant.E3SPEAKER_ACTIVE.equals(event.getType())) {
      if(logger.isDebugEnabled()) {
        logger.debug("E3SPEAKER_ACTIVE added: {}", event.getInstance());
      }
    }
  }

  /**
   * IInstanceListener implementation
   */
  @Override
  public synchronized void instanceRemoved(InstanceEvent event) {
    if (E3Constant.E3GATEWAY.equals(event.getType())) {
      //upGateways.remove(event.getInstance());
      if(logger.isDebugEnabled()) {
        logger.debug("E3GATEWAY removed: {}", event.getInstance());
      }
    }
    else if (E3Constant.E3SPEAKER.equals(event.getType())) {
      //upSpeakers.remove(event.getInstance());
      if(logger.isDebugEnabled()) {
        logger.debug("E3SPEAKER removed: {}", event.getInstance());
      }
    }
    else if (E3Constant.E3GATEWAY_ACTIVE.equals(event.getType())) {
      if(logger.isDebugEnabled()) {
        logger.debug("E3GATEWAY_ACTIVE removed: {}", event.getInstance());
      }
    }
    else if (E3Constant.E3SPEAKER_ACTIVE.equals(event.getType())) {
      if(logger.isDebugEnabled()) {
        logger.debug("E3SPEAKER_ACTIVE removed: {}", event.getInstance());
      }
    }
  }

  public void setRunning(boolean running) {
    this.running = running;
  }
}
TOP

Related Classes of com.alu.e3.topology.TopologyWatcher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.