/* * Copyright 2014 the original author or authors. * * 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.springframework.xd.dirt.server.admin.deployment; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.StringUtils; import org.springframework.xd.dirt.core.DeploymentUnit; import org.springframework.xd.dirt.core.DeploymentUnitStatus; import org.springframework.xd.module.ModuleDeploymentProperties; import org.springframework.xd.module.ModuleDescriptor; /** * Default {@link org.springframework.xd.dirt.server.admin.deployment.DeploymentUnitStateCalculator} * implementation for streams and jobs. This implementation uses the following * criteria: * <ul> * <li>If all expected modules are deployed, the state is considered * {@link org.springframework.xd.dirt.core.DeploymentUnitStatus.State#deployed deployed}.</li> * <li>If one or more of the modules do not have the number of expected * instances but there is at least one instance of each module, * the state is considered * {@link org.springframework.xd.dirt.core.DeploymentUnitStatus.State#incomplete incomplete}.</li> * <li>If one or more of the modules do not have any instances deployed, * the state is considered * {@link org.springframework.xd.dirt.core.DeploymentUnitStatus.State#failed failed}.</li> * </ul> * * @author Patrick Peralta */ public class DefaultDeploymentUnitStateCalculator implements DeploymentUnitStateCalculator { /** * Logger. */ private static final Logger logger = LoggerFactory.getLogger(DefaultDeploymentUnitStateCalculator.class); /** * {@inheritDoc} */ @Override public DeploymentUnitStatus calculate(DeploymentUnit deploymentUnit, ModuleDeploymentPropertiesProvider<ModuleDeploymentProperties> provider, Collection<ModuleDeploymentStatus> deploymentStatuses) { Map<ModuleDescriptor.Key, Count> moduleCount = new HashMap<ModuleDescriptor.Key, Count>(); for (ModuleDescriptor descriptor : deploymentUnit.getModuleDescriptors()) { moduleCount.put(descriptor.createKey(), new Count(provider.propertiesForDescriptor(descriptor).getCount())); } StringBuilder builder = new StringBuilder(); logger.debug("Evaluating state for {}", deploymentUnit.getName()); logger.trace("moduleCountMap: {}", moduleCount); for (ModuleDeploymentStatus deploymentStatus : deploymentStatuses) { logger.trace("\t{}", deploymentStatus); if (deploymentStatus.getState() == ModuleDeploymentStatus.State.deployed) { ModuleDescriptor.Key key = deploymentStatus.getKey(); Count count = moduleCount.get(key); if (count != null && (count.expected == 0 || ++count.actual == count.expected)) { moduleCount.remove(key); } } else if (StringUtils.hasText(deploymentStatus.getErrorDescription())) { if (builder.length() > 0) { builder.append("; "); } builder.append(deploymentStatus.getErrorDescription()); } } logger.trace("moduleCountMap after evaluation: {}", moduleCount); if (moduleCount.isEmpty()) { return new DeploymentUnitStatus(DeploymentUnitStatus.State.deployed, builder.toString()); } // since there are some modules that did not meet the expected count, // iterate the map and determine if any modules failed to deploy at all; // if each module type has at least one deployment the status is considered // incomplete boolean failed = false; for (Count count : moduleCount.values()) { if (count.actual == 0) { failed = true; break; } } DeploymentUnitStatus.State state = (failed) ? DeploymentUnitStatus.State.failed : DeploymentUnitStatus.State.incomplete; return new DeploymentUnitStatus(state, builder.toString()); } /** * Structure to track the number of expected and actual module deployments. */ private static class Count { /** * The number of expected module instances. */ final int expected; /** * The number of actual module instances. */ int actual; /** * Construct a {@code Count} with the expected module count. * * @param expected expected number of modules */ private Count(int expected) { this.expected = expected; } /** * {@inheritDoc} */ @Override public String toString() { return "Count{" + "expected=" + expected + ", actual=" + actual + '}'; } } }