package org.ovirt.engine.core.bll; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VdcReturnValueBase; import org.ovirt.engine.core.compat.LogCompat; import org.ovirt.engine.core.compat.LogFactoryCompat; import org.ovirt.engine.core.utils.threadpool.ThreadPoolUtil; public class MultipleActionsRunner { private final int CONCURRENT_ACTIONS = 10; private VdcActionType _actionType = VdcActionType.forValue(0); private List<VdcActionParametersBase> _parameters; private final java.util.ArrayList<CommandBase> _commands = new java.util.ArrayList<CommandBase>(); protected boolean isInternal; public MultipleActionsRunner(VdcActionType actionType, List<VdcActionParametersBase> parameters, boolean isInternal) { _actionType = actionType; _parameters = parameters; this.isInternal = isInternal; } protected List<VdcActionParametersBase> getParameters() { return _parameters; } protected java.util.ArrayList<CommandBase> getCommands() { return _commands; } public java.util.ArrayList<VdcReturnValueBase> Execute() { // sanity - don't do anything if no parameters passed if (_parameters == null || _parameters.isEmpty()) { log.infoFormat("{0} of type {1} invoked with no actions", this.getClass().getSimpleName(), _actionType); return new ArrayList<VdcReturnValueBase>(); } java.util.ArrayList<VdcReturnValueBase> returnValues = new java.util.ArrayList<VdcReturnValueBase>(); try { for (VdcActionParametersBase parameter : getParameters()) { parameter.setMultipleAction(true); CommandBase command = CommandsFactory.CreateCommand(_actionType, parameter); command.setInternalExecution(isInternal); getCommands().add(command); } if (getCommands().size() == 1) { returnValues.add(getCommands().get(0).CanDoActionOnly()); } else { CheckCanDoActionsAsyncroniousely(returnValues); } ThreadPoolUtil.execute(new Runnable() { @Override public void run() { RunCommands(); } }); } catch (RuntimeException e) { log.error("Failed to execute multiple actions of type: " + _actionType, e); } return returnValues; } /** * Check CanDoActions of all commands. We perform checks for all commands at * the same time the number of threads is managed by java * * @param returnValues * @param executorService */ private void CheckCanDoActionsAsyncroniousely( java.util.ArrayList<VdcReturnValueBase> returnValues) { for (int i = 0; i < getCommands().size(); i += CONCURRENT_ACTIONS) { int handleSize = Math.min(CONCURRENT_ACTIONS, getCommands().size() - i); CountDownLatch latch = new CountDownLatch(handleSize); int fixedSize = i + handleSize; for (int j = i; j < fixedSize; j++) { RunCanDoActionAsyncroniousely(returnValues, j, fixedSize, latch); } try { latch.await(); } catch (InterruptedException e) { } } } private void RunCanDoActionAsyncroniousely( final java.util.ArrayList<VdcReturnValueBase> returnValues, final int currentCanDoActionId, final int totalSize, final CountDownLatch latch) { ThreadPoolUtil.execute(new Runnable() { @Override public void run() { CommandBase command = getCommands().get(currentCanDoActionId); if (command != null) { String actionType = command.getActionType().toString(); try { log.infoFormat("Start time: {0}. Start running CanDoAction for command number {1}/{2} (Command type: {3})", new java.util.Date(), currentCanDoActionId + 1, totalSize, actionType); VdcReturnValueBase returnValue = command.CanDoActionOnly(); synchronized (returnValues) { returnValues.add(returnValue); } } catch (RuntimeException e) { log.errorFormat("Failed to execute CanDoAction() for command number {0}/{1} (Command type: {2}), Error: {3}", currentCanDoActionId + 1, totalSize, actionType, e); } finally { latch.countDown(); log.infoFormat("End time: {0}. Finish handling CanDoAction for command number {1}/{2} (Command type: {3})", new java.util.Date(), currentCanDoActionId + 1, totalSize, actionType); } } else { log.errorFormat("Failed to execute CanDoAction() for command number {0}/{1}. Command is null.", currentCanDoActionId + 1, totalSize); } } }); } protected void RunCommands() { for (CommandBase command : getCommands()) { if (command.getReturnValue().getCanDoAction()) { command.ExecuteAction(); } } } private static LogCompat log = LogFactoryCompat.getLog(MultipleActionsRunner.class); }