| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * 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 org.apache.slider.providers.agent; |
| |
| import org.apache.slider.providers.agent.application.metadata.CommandOrder; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Stores the command dependency order for all components in a service. <commandOrder> |
| * <command>SUPERVISOR-START</command> <requires>NIMBUS-STARTED</requires> </commandOrder> Means, SUPERVISOR START |
| * requires NIMBUS to be STARTED |
| */ |
| public class ComponentCommandOrder { |
| public static final Logger log = |
| LoggerFactory.getLogger(ComponentCommandOrder.class); |
| private static char SPLIT_CHAR = '-'; |
| Map<Command, Map<String, List<ComponentState>>> dependencies = |
| new HashMap<Command, Map<String, List<ComponentState>>>(); |
| |
| public ComponentCommandOrder(List<CommandOrder> commandOrders) { |
| if (commandOrders != null && commandOrders.size() > 0) { |
| for (CommandOrder commandOrder : commandOrders) { |
| ComponentCommand componentCmd = getComponentCommand(commandOrder.getCommand()); |
| String requires = commandOrder.getRequires(); |
| List<ComponentState> requiredStates = parseRequiredStates(requires); |
| if (requiredStates.size() > 0) { |
| Map<String, List<ComponentState>> compDep = dependencies.get(componentCmd.command); |
| if (compDep == null) { |
| compDep = new HashMap<String, List<ComponentState>>(); |
| dependencies.put(componentCmd.command, compDep); |
| } |
| |
| List<ComponentState> requirements = compDep.get(componentCmd.componentName); |
| if (requirements == null) { |
| requirements = new ArrayList<ComponentState>(); |
| compDep.put(componentCmd.componentName, requirements); |
| } |
| |
| requirements.addAll(requiredStates); |
| } |
| } |
| } |
| } |
| |
| private List<ComponentState> parseRequiredStates(String requires) { |
| if (requires == null || requires.length() < 2) { |
| throw new IllegalArgumentException("Input cannot be null and must contain component and state."); |
| } |
| |
| String[] componentStates = requires.split(","); |
| List<ComponentState> retList = new ArrayList<ComponentState>(); |
| for (String componentStateStr : componentStates) { |
| retList.add(getComponentState(componentStateStr)); |
| } |
| |
| return retList; |
| } |
| |
| private ComponentCommand getComponentCommand(String compCmdStr) { |
| if (compCmdStr == null || compCmdStr.trim().length() < 2) { |
| throw new IllegalArgumentException("Input cannot be null and must contain component and command."); |
| } |
| |
| compCmdStr = compCmdStr.trim(); |
| int splitIndex = compCmdStr.lastIndexOf(SPLIT_CHAR); |
| if (splitIndex == -1 || splitIndex == 0 || splitIndex == compCmdStr.length() - 1) { |
| throw new IllegalArgumentException("Input does not appear to be well-formed."); |
| } |
| String compStr = compCmdStr.substring(0, splitIndex); |
| String cmdStr = compCmdStr.substring(splitIndex + 1); |
| |
| Command cmd = Command.valueOf(cmdStr); |
| |
| if (cmd != Command.START) { |
| throw new IllegalArgumentException("Dependency order can only be specified for START."); |
| } |
| return new ComponentCommand(compStr, cmd); |
| } |
| |
| private ComponentState getComponentState(String compStStr) { |
| if (compStStr == null || compStStr.trim().length() < 2) { |
| throw new IllegalArgumentException("Input cannot be null."); |
| } |
| |
| compStStr = compStStr.trim(); |
| int splitIndex = compStStr.lastIndexOf(SPLIT_CHAR); |
| if (splitIndex == -1 || splitIndex == 0 || splitIndex == compStStr.length() - 1) { |
| throw new IllegalArgumentException("Input does not appear to be well-formed."); |
| } |
| String compStr = compStStr.substring(0, splitIndex); |
| String stateStr = compStStr.substring(splitIndex + 1); |
| |
| State state = State.valueOf(stateStr); |
| if (state != State.STARTED && state != State.INSTALLED) { |
| throw new IllegalArgumentException("Dependency order can only be specified against STARTED/INSTALLED."); |
| } |
| return new ComponentState(compStr, state); |
| } |
| |
| public boolean canExecute(String component, Command command, Collection<ComponentInstanceState> currentStates) { |
| boolean canExecute = true; |
| if (dependencies.containsKey(command) && dependencies.get(command).containsKey(component)) { |
| List<ComponentState> required = dependencies.get(command).get(component); |
| for (ComponentState stateToMatch : required) { |
| for (ComponentInstanceState currState : currentStates) { |
| log.debug("Checking schedule {} {} against dependency {} is {}", |
| component, command, currState.getComponentName(), currState.getState()); |
| if (currState.getComponentName().equals(stateToMatch.componentName)) { |
| if (currState.getState() != stateToMatch.state) { |
| if (stateToMatch.state == State.STARTED) { |
| log.info("Cannot schedule {} {} as dependency {} is {}", |
| component, command, currState.getComponentName(), currState.getState()); |
| canExecute = false; |
| } else { |
| //state is INSTALLED |
| if (currState.getState() != State.STARTING && currState.getState() != State.STARTED) { |
| log.info("Cannot schedule {} {} as dependency {} is {}", |
| component, command, currState.getComponentName(), currState.getState()); |
| canExecute = false; |
| } |
| } |
| } |
| } |
| if (!canExecute) { |
| break; |
| } |
| } |
| if (!canExecute) { |
| break; |
| } |
| } |
| } |
| |
| return canExecute; |
| } |
| |
| static class ComponentState { |
| public String componentName; |
| public State state; |
| |
| public ComponentState(String componentName, State state) { |
| this.componentName = componentName; |
| this.state = state; |
| } |
| } |
| |
| static class ComponentCommand { |
| public String componentName; |
| public Command command; |
| |
| public ComponentCommand(String componentName, Command command) { |
| this.componentName = componentName; |
| this.command = command; |
| } |
| } |
| } |