Package org.ngrinder.agent.service

Source Code of org.ngrinder.agent.service.AgentManagerService

/*
* Licensed 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 org.ngrinder.agent.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.grinder.common.processidentity.AgentIdentity;
import net.grinder.engine.controller.AgentControllerIdentityImplementation;
import net.grinder.message.console.AgentControllerState;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.mutable.MutableInt;
import org.ngrinder.agent.repository.AgentManagerRepository;
import org.ngrinder.common.constant.ControllerConstants;
import org.ngrinder.infra.config.Config;
import org.ngrinder.infra.schedule.ScheduledTaskService;
import org.ngrinder.model.AgentInfo;
import org.ngrinder.model.User;
import org.ngrinder.monitor.controller.model.SystemDataModel;
import org.ngrinder.perftest.service.AgentManager;
import org.ngrinder.service.AbstractAgentManagerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.*;

import static org.ngrinder.common.util.CollectionUtils.newArrayList;
import static org.ngrinder.common.util.CollectionUtils.newHashMap;
import static org.ngrinder.common.util.NoOp.noOp;
import static org.ngrinder.common.util.TypeConvertUtils.cast;

/**
* Agent manager service.
*
* @author JunHo Yoon
* @since 3.0
*/
public class AgentManagerService extends AbstractAgentManagerService {
  protected static final Logger LOGGER = LoggerFactory.getLogger(AgentManagerService.class);

  @Autowired
  private AgentManager agentManager;

  @Autowired
  protected AgentManagerRepository agentManagerRepository;

  @Autowired
  protected LocalAgentService cachedLocalAgentService;

  @Autowired
  private Config config;

  @Autowired
  protected ScheduledTaskService scheduledTaskService;

  private Runnable runnable;

  @PostConstruct
  public void init() {
    runnable = new Runnable() {
      @Override
      public void run() {
        checkAgentStatePeriodically();
      }
    };
    scheduledTaskService.addFixedDelayedScheduledTaskInTransactionContext(runnable, 1000);
  }

  @PreDestroy
  public void destroy() {
    scheduledTaskService.removeScheduledJob(runnable);
  }

  public void checkAgentStatePeriodically() {
    checkAgentState();
  }

  public void checkAgentState() {
    List<AgentInfo> newAgents = newArrayList(0);
    List<AgentInfo> updatedAgents = newArrayList(0);
    List<AgentInfo> stateUpdatedAgents = newArrayList(0);
    List<AgentInfo> removedAgents = newArrayList(0);

    Set<AgentIdentity> allAttachedAgents = getAgentManager().getAllAttachedAgents();
    Map<String, AgentControllerIdentityImplementation> attachedAgentMap = Maps.newHashMap();
    for (AgentIdentity agentIdentity : allAttachedAgents) {
      AgentControllerIdentityImplementation agentControllerIdentity = cast(agentIdentity);
      attachedAgentMap.put(createKey(agentControllerIdentity), agentControllerIdentity);
    }

    // If region is not specified retrieved all
    Map<String, AgentInfo> agentInDBMap = newHashMap();
    // step1. check all agents in DB, whether they are attached to
    // controller.
    for (AgentInfo each : getAllLocal()) {
      final String agentKey = createKey(each);
      if (!agentInDBMap.containsKey(agentKey)) {
        agentInDBMap.put(agentKey, each);
      } else {
        removedAgents.add(each);
      }
    }

    for (Map.Entry<String, AgentInfo> each : agentInDBMap.entrySet()) {
      String agentKey = each.getKey();
      AgentInfo agentInfo = each.getValue();
      AgentControllerIdentityImplementation agentIdentity = attachedAgentMap.remove(agentKey);
      if (agentIdentity == null) {
        // this agent is not attached to controller
        agentInfo.setState(AgentControllerState.INACTIVE);
        stateUpdatedAgents.add(agentInfo);
      } else if (!hasSameInfo(agentInfo, agentIdentity)) {
        agentInfo.setRegion(agentIdentity.getRegion());
        agentInfo.setPort(agentManager.getAgentConnectingPort(agentIdentity));
        agentInfo.setVersion(agentManager.getAgentVersion(agentIdentity));
        updatedAgents.add(agentInfo);
      } else if (!hasSameState(agentInfo, agentIdentity)) {
        agentInfo.setState(agentManager.getAgentState(agentIdentity));
        stateUpdatedAgents.add(agentInfo);
      }
    }

    // step2. check all attached agents, whether they are new, and not saved
    // in DB.
    for (AgentControllerIdentityImplementation agentIdentity : attachedAgentMap.values()) {
      final AgentInfo agentInfo = fillUp(new AgentInfo(), agentIdentity);
      newAgents.add(agentInfo);
    }
    cachedLocalAgentService.updateAgents(newAgents, updatedAgents, stateUpdatedAgents, removedAgents);
    if (!newAgents.isEmpty() || !removedAgents.isEmpty()) {
      expireLocalCache();
    }
  }

  public String extractRegionFromAgentRegion(String agentRegion) {
    if (agentRegion != null && agentRegion.contains("_owned_")) {
      return agentRegion.substring(0, agentRegion.indexOf("_owned_"));
    }
    if (agentRegion != null && agentRegion.contains("owned_")) {
      return agentRegion.substring(0, agentRegion.indexOf("owned_"));
    }
    if (StringUtils.isEmpty(agentRegion)) {
      return Config.NONE_REGION;
    }
    return agentRegion;
  }

  protected boolean hasSameInfo(AgentInfo agentInfo, AgentControllerIdentityImplementation agentIdentity) {
    return agentInfo != null &&
        agentInfo.getPort() == agentManager.getAgentConnectingPort(agentIdentity) &&
        StringUtils.equals(agentInfo.getRegion(), agentIdentity.getRegion()) &&
        StringUtils.equals(StringUtils.trimToNull(agentInfo.getVersion()),
            StringUtils.trimToNull(agentManager.getAgentVersion(agentIdentity)));
  }

  protected boolean hasSameState(AgentInfo agentInfo, AgentControllerIdentityImplementation agentIdentity) {
    return agentInfo != null &&
        agentInfo.getState() == agentManager.getAgentState(agentIdentity);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.ngrinder.service.IAgentManagerService#getAvailableAgentCountMap
   * (org.ngrinder .model.User)
   */
  @Override
  public Map<String, MutableInt> getAvailableAgentCountMap(User user) {
    int availableShareAgents = 0;
    int availableUserOwnAgent = 0;
    String myAgentSuffix = "owned_" + user.getUserId();
    for (AgentInfo agentInfo : getAllActive()) {
      // Skip all agents which are disapproved, inactive or
      // have no region prefix.
      if (!agentInfo.isApproved()) {
        continue;
      }
      String fullRegion = agentInfo.getRegion();
      // It's this controller's agent
      if (StringUtils.endsWithIgnoreCase(fullRegion, myAgentSuffix)) {
        availableUserOwnAgent++;
      } else if (!StringUtils.containsIgnoreCase(fullRegion, "owned_")) {
        availableShareAgents++;
      }
    }

    int maxAgentSizePerConsole = getMaxAgentSizePerConsole();
    availableShareAgents = (Math.min(availableShareAgents, maxAgentSizePerConsole));
    Map<String, MutableInt> result = new HashMap<String, MutableInt>(1);
    result.put(Config.NONE_REGION, new MutableInt(availableShareAgents + availableUserOwnAgent));
    return result;
  }

  int getMaxAgentSizePerConsole() {
    return getAgentManager().getMaxAgentSizePerConsole();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ngrinder.service.IAgentManagerService#getAllLocalWithFullInfo()
   */
  @Override
  @Transactional
  public List<AgentInfo> getAllLocalWithFullInfo() {
    Map<String, AgentInfo> agentInfoMap = createLocalAgentMap();
    Set<AgentIdentity> allAttachedAgents = getAgentManager().getAllAttachedAgents();
    List<AgentInfo> agentList = new ArrayList<AgentInfo>(allAttachedAgents.size());
    for (AgentIdentity eachAgentIdentity : allAttachedAgents) {
      AgentControllerIdentityImplementation agentControllerIdentity = cast(eachAgentIdentity);
      agentList.add(createAgentInfo(agentControllerIdentity, agentInfoMap));
    }
    return agentList;
  }

  private Map<String, AgentInfo> createLocalAgentMap() {
    Map<String, AgentInfo> agentInfoMap = Maps.newHashMap();
    for (AgentInfo each : getAllLocal()) {
      agentInfoMap.put(createKey(each), each);
    }
    return agentInfoMap;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.ngrinder.service.IAgentManagerService#createKey(org.ngrinder
   * .agent.model.AgentInfo )
   */
  @Override
  public String createKey(AgentInfo agentInfo) {
    return createAgentKey(agentInfo.getIp(), agentInfo.getName());
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.ngrinder.service.IAgentManagerService#createKey(net.grinder
   * .engine.controller .AgentControllerIdentityImplementation)
   */
  @Override
  public String createKey(AgentControllerIdentityImplementation agentIdentity) {
    return createAgentKey(agentIdentity.getIp(), agentIdentity.getName());
  }

  protected String createAgentKey(String ip, String name) {
    return ip + "_" + name;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ngrinder.service.IAgentManagerService#
   * getAgentIdentityByIpAndName(java.lang .String, java.lang.String)
   */
  @Override
  public AgentControllerIdentityImplementation getAgentIdentityByIpAndName(String ip, String name) {
    Set<AgentIdentity> allAttachedAgents = getAgentManager().getAllAttachedAgents();
    for (AgentIdentity eachAgentIdentity : allAttachedAgents) {
      AgentControllerIdentityImplementation agentIdentity = cast(eachAgentIdentity);
      if (StringUtils.equals(ip, agentIdentity.getIp()) && StringUtils.equals(name, agentIdentity.getName())) {
        return agentIdentity;
      }
    }
    return null;
  }


  public List<AgentInfo> getAllLocal() {
    return Collections.unmodifiableList(cachedLocalAgentService.getLocalAgents());
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.ngrinder.service.IAgentManagerService#getAllActive
   * ()
   *
   */
  @Override
  public List<AgentInfo> getAllActive() {
    List<AgentInfo> agents = Lists.newArrayList();
    for (AgentInfo agentInfo : getAllLocal()) {
      final AgentControllerState state = agentInfo.getState();
      if (state != null && state.isActive()) {
        agents.add(agentInfo);
      }
    }
    return agents;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.ngrinder.service.IAgentManagerService#getAllVisible
   * ()
   */
  @Override
  public List<AgentInfo> getAllVisible() {
    List<AgentInfo> agents = Lists.newArrayList();
    for (AgentInfo agentInfo : getAllLocal()) {
      final AgentControllerState state = agentInfo.getState();
      if (state != null && state.isActive()) {
        agents.add(agentInfo);
      }
    }
    return agents;
  }

  private AgentInfo createAgentInfo(AgentControllerIdentityImplementation agentIdentity,
                                    Map<String, AgentInfo> agentInfoMap) {
    AgentInfo agentInfo = agentInfoMap.get(createKey(agentIdentity));
    if (agentInfo == null) {
      agentInfo = new AgentInfo();
    }
    return fillUp(agentInfo, agentIdentity);
  }

  protected AgentInfo fillUp(AgentInfo agentInfo, AgentControllerIdentityImplementation agentIdentity) {
    fillUpApproval(agentInfo);
    if (agentIdentity != null) {
      agentInfo.setAgentIdentity(agentIdentity);
      agentInfo.setName(agentIdentity.getName());
      agentInfo.setRegion(agentIdentity.getRegion());
      agentInfo.setIp(agentIdentity.getIp());
      AgentManager agentManager = getAgentManager();
      agentInfo.setPort(agentManager.getAgentConnectingPort(agentIdentity));
      agentInfo.setState(agentManager.getAgentState(agentIdentity));
      agentInfo.setVersion(agentManager.getAgentVersion(agentIdentity));
    }
    return agentInfo;
  }

  protected AgentInfo fillUpApproval(AgentInfo agentInfo) {
    if (agentInfo.getApproved() == null) {
      final boolean approved = config.getControllerProperties().getPropertyBoolean(ControllerConstants
          .PROP_CONTROLLER_ENABLE_AGENT_AUTO_APPROVAL);
      agentInfo.setApproved(approved);
    }
    return agentInfo;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ngrinder.service.IAgentManagerService#getAll(long,
   * boolean)
   */
  @Override
  public AgentInfo getOne(Long id) {
    return getOne(id, false);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ngrinder.service.IAgentManagerService#getAll(long,
   * boolean)
   */
  @Override
  public AgentInfo getOne(Long id, boolean includeAgentIdentity) {
    AgentInfo findOne = agentManagerRepository.findOne(id);
    if (findOne == null) {
      return null;
    }
    if (includeAgentIdentity) {
      AgentControllerIdentityImplementation agentIdentityByIp = getAgentIdentityByIpAndName(findOne.getIp(),
          findOne.getName());
      return fillUp(findOne, agentIdentityByIp);
    } else {
      return findOne;
    }
  }

  /**
   * Approve/disapprove the agent on given id.
   *
   * @param id      id
   * @param approve true/false
   */
  @Transactional
  public AgentInfo approve(Long id, boolean approve) {
    AgentInfo found = agentManagerRepository.findOne(id);
    if (found != null) {
      found.setApproved(approve);
      agentManagerRepository.save(found);
      expireLocalCache();
    }
    return found;
  }

  /**
   * Stop agent. If it's in cluster mode, it queue to agentRequestCache.
   * otherwise, it send stop message to the agent.
   *
   * @param id identity of agent to stop.
   */
  @Transactional
  public void stopAgent(Long id) {
    AgentInfo agent = getOne(id, true);
    if (agent == null) {
      return;
    }
    getAgentManager().stopAgent(agent.getAgentIdentity());
  }

  /**
   * Add the agent system data model share request on cache.
   *
   * @param id agent id.
   */
  public void requestShareAgentSystemDataModel(Long id) {
    noOp();
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.ngrinder.service.IAgentManagerService#getSystemDataModel
   * (java.lang.String, java.lang.String)
   */
  @Override
  public SystemDataModel getSystemDataModel(String ip, String name) {
    AgentControllerIdentityImplementation agentIdentity = getAgentIdentityByIpAndName(ip, name);
    return agentIdentity != null ? getAgentManager().getSystemDataModel(agentIdentity) : new SystemDataModel();
  }

  AgentManager getAgentManager() {
    return agentManager;
  }

  void setAgentManager(AgentManager agentManager) {
    this.agentManager = agentManager;
  }

  public void setAgentManagerRepository(AgentManagerRepository agentManagerRepository) {
    this.agentManagerRepository = agentManagerRepository;
  }

  public Config getConfig() {
    return config;
  }

  public void setConfig(Config config) {
    this.config = config;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.ngrinder.service.IAgentManagerService#updateAgentLib
   * (java.lang.String)
   */
  @Override
  public void update(Long id) {
    AgentInfo agent = getOne(id, true);
    if (agent == null) {
      return;
    }
    updateAgent(agent.getAgentIdentity());
  }

  /**
   * Update the agent
   *
   * @param agentIdentity agent identity to be updated.
   */
  public void updateAgent(AgentIdentity agentIdentity) {
    agentManager.updateAgent(agentIdentity, shouldUpdateAgentAlways() ? "99.99" : config.getVersion());
  }


  protected boolean shouldUpdateAgentAlways() {
    return config.getControllerProperties().getPropertyBoolean(ControllerConstants.PROP_CONTROLLER_AGENT_FORCE_UPDATE);
  }


  public void expireLocalCache() {
    cachedLocalAgentService.expireCache();
  }

  /**
   * Clean up the agents from db which belongs to the inactive regions.
   * Do nothing in not cluster mode.
   */
  @Transactional
  public void cleanup() {
    for (AgentInfo each : agentManagerRepository.findAll()) {
      if (!each.getState().isActive()) {
        agentManagerRepository.delete(each);
      }
    }
  }
}
TOP

Related Classes of org.ngrinder.agent.service.AgentManagerService

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.