/** * Copyright (C) 2008 Progress Software, Inc. All rights reserved. * http://fusesource.com * * The software in this package is published under the terms of the AGPL license * a copy of which has been included with this distribution in the license.txt file. */ package org.fusesource.cloudmix.common.controller; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.fusesource.cloudmix.common.GridController; import org.fusesource.cloudmix.common.controller.constraints.agent.AgentContainerTypeChecker; import org.fusesource.cloudmix.common.controller.constraints.agent.AgentLivenessChecker; import org.fusesource.cloudmix.common.controller.constraints.agent.AgentMaxFeaturesChecker; import org.fusesource.cloudmix.common.controller.constraints.agent.AgentOwnedByFeatureChecker; import org.fusesource.cloudmix.common.controller.constraints.agent.AgentPackageSupportChecker; import org.fusesource.cloudmix.common.controller.constraints.agent.AgentPreferedHostChecker; import org.fusesource.cloudmix.common.controller.constraints.agent.AgentProfileChecker; import org.fusesource.cloudmix.common.controller.constraints.agent.IAgentConstraintChecker; import org.fusesource.cloudmix.common.dto.Dependency; import org.fusesource.cloudmix.common.dto.DependencyStatus; import org.fusesource.cloudmix.common.dto.FeatureDetails; /** * @version $Revision$ */ public class FeatureController { private static final transient Log LOG = LogFactory.getLog(FeatureController.class); private static final List<IAgentConstraintChecker> CHECKERS = new ArrayList<IAgentConstraintChecker>(); static { CHECKERS.add(new AgentProfileChecker()); CHECKERS.add(new AgentLivenessChecker()); CHECKERS.add(new AgentPackageSupportChecker()); CHECKERS.add(new AgentOwnedByFeatureChecker()); CHECKERS.add(new AgentMaxFeaturesChecker()); CHECKERS.add(new AgentPreferedHostChecker()); CHECKERS.add(new AgentContainerTypeChecker()); } private GridController client; private FeatureDetails details; public FeatureController(GridController client, FeatureDetails details) { this.client = client; this.details = details; } public AgentController selectAgentForDeployment(String profileID, Collection<AgentController> candidates) { LOG.debug("Selecting agent for deployment for " + profileID + " feature " + this + " from: " + candidates); for (IAgentConstraintChecker checker : CHECKERS) { candidates = checker.applyConstraint(profileID, this, candidates); LOG.debug("Number of candidates after running checker " + checker.getClass().getSimpleName() + ": " + candidates.size()); } return getAgentWithTheLeastAmountOfFeatures(candidates); } public boolean areDependanciesInstanciated(String profileID) { List<Dependency> list = getDependencies(); for (Dependency dependency : list) { FeatureController controller = client.getFeatureController(dependency); if (controller == null) { LOG.warn("No FeatureController yet for: " + dependency); return false; } if (!controller.hasAtLeastMinimumInstances(profileID)) { if (LOG.isDebugEnabled()) { LOG.debug("Cannot deploy " + getId() + " due to not enough instances of: " + dependency); } return false; } } return true; } public static AgentController getAgentWithTheLeastAmountOfFeatures(Collection<AgentController> agents) { AgentController answer = null; for (AgentController agent : agents) { if (answer == null) { answer = agent; } else if (agent.getFeatures().size() < answer.getFeatures().size()) { answer = agent; } } return answer; } /** * checks that a given agent is on one of the preferred host of the feature. * Note that if the feature doesn't specify any particular host then any * host is deemed "preferred" * * @param agent * @return */ public boolean isAgentOnAPreferredMachine(AgentController agent) { return getDetails().getPreferredMachines() == null || getDetails().getPreferredMachines().size() == 0 || getDetails().getPreferredMachines().contains(agent.getDetails().getHostname()); } /** * Returns true if the minimum number of instances are currently deployed. * * @return true if the minimum number of instances are currently deployed */ public boolean hasAtLeastMinimumInstances(String profileID) { int actual = instanceCount(profileID, true); int expected = Integer.parseInt(getDetails().getMinimumInstances()); return actual >= expected; } /** * Returns true if the maximum number of instances are currently assigned to * be deployed (i.e. no more can be deployed) * * @return true if the maximum number of instances are currently assigned to * be deployed */ public boolean canDeployMoreInstances(String profileID) { int actual = instanceCount(profileID, false); int expected = Integer.parseInt(getDetails().getMaximumInstances()); return actual < expected; } /** * Return the number of instances of this feature */ private int instanceCount(String profileID, boolean onlyIfDeployed) { return client.getFeatureInstanceCount(getId(), profileID, onlyIfDeployed); } // Properties //------------------------------------------------------------------------- public String getId() { return details.getId(); } public String getResource() { return details.getResource(); } public List<Dependency> getDependencies() { return details.getDependencies(); } public Set<String> getPreferredMachines() { return details.getPreferredMachines(); } public FeatureDetails getDetails() { return details; } public DependencyStatus getStatus(String profileId) { DependencyStatus answer = new DependencyStatus(getId()); answer.setProvisioned(hasAtLeastMinimumInstances(profileId)); return answer; } public String toString() { return "FeatureController for " + details.getId(); } }