content: //
  // 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 com.cloud.network.utils;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
  import java.util.concurrent.ConcurrentHashMap;
  
  import org.apache.logging.log4j.Logger;
  import org.apache.logging.log4j.LogManager;
  
  import com.cloud.agent.api.Answer;
  import com.cloud.agent.api.Command;
  import com.cloud.resource.ServerResource;
  
  public class CommandRetryUtility {
  
      protected Logger logger = LogManager.getLogger(getClass());
  
      private static final int ZERO = 0;
      private static CommandRetryUtility instance;
  
      static {
          instance = new CommandRetryUtility();
      }
  
      private final ConcurrentHashMap<Command, Integer> commandsToRetry;
      private ServerResource serverResource;
  
      private CommandRetryUtility() {
          commandsToRetry = new ConcurrentHashMap<Command, Integer>();
      }
  
      public static CommandRetryUtility getInstance() {
          return instance;
      }
  
      public void setServerResource(final ServerResource serverResource) {
          this.serverResource = serverResource;
      }
  
      public boolean addRetry(final Command command, final int retries) {
          if (commandsToRetry.containsKey(command)) {
              // A retry already exists for this command, do not add it again.
              // Once all retries are executed, the command will be removed from the map.
              return false;
          }
          commandsToRetry.put(command, retries);
          return true;
      }
  
      public Answer retry(final Command command, final Class<? extends Answer> answerClass, final Exception error) {
          if (commandsToRetry.containsKey(command)) {
              Integer numRetries = commandsToRetry.get(command);
  
              if (numRetries > ZERO) {
                  commandsToRetry.put(command, --numRetries);
  
                  logger.warn("Retrying " + command.getClass().getSimpleName() + ". Number of retries remaining: " + numRetries);
  
                  return serverResource.executeRequest(command);
              } else {
                  commandsToRetry.remove(command);
              }
          }
          try {
              final Constructor<? extends Answer> answerConstructor = answerClass.getConstructor(Command.class, Exception.class);
              return answerConstructor.newInstance(command, error);
          } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
              return Answer.createUnsupportedCommandAnswer(command);
          }
      }
  }
  