/* * Strongback * Copyright 2015, Strongback and individual contributors by the @authors tag. * See the COPYRIGHT.txt in the distribution for a full listing of individual * contributors. * * Licensed under the MIT License; you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://opensource.org/licenses/MIT * 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.strongback.command; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.Set; final class Commands { private final Queue<CommandRunner> beingExecuted = new LinkedList<>(); private final Queue<CommandRunner> pendingAddition = new LinkedList<>(); private final Map<Requirable, CommandRunner> inUse = new HashMap<>(); public Commands() { } public void step(long timeInMillis) { int pendingLength = pendingAddition.size(); for (int i = 0; i < pendingLength; i++) if (reserve(pendingAddition.peek())) { pendingAddition.poll(); } else { // What to do if can't reserve requirement // As of now, don't even try again pendingAddition.poll(); } // Run all of the commands, if one is done, don't put it back in the queue int initialSize = beingExecuted.size(); for (int i = 0; i < initialSize; i++) { CommandRunner runner = beingExecuted.poll(); if (runner.step(timeInMillis)) { remove(runner); } else { beingExecuted.offer(runner); } } } void add(CommandRunner command) { // Add the command runner pendingAddition.offer(command); } private boolean reserve(CommandRunner command) { Set<Requirable> requirements = command.getRequired(); // Verify that every requirement can be obtained for (Requirable required : requirements) { CommandRunner user = inUse.get(required); if (user != null && !user.isInterruptible()) return false; } // Reserve the requirements for (Requirable required : requirements) { if (inUse.containsKey(required)) inUse.get(required).cancel(); inUse.put(required, command); } beingExecuted.offer(command); return true; } private void remove(CommandRunner runner) { runner.getRequired().forEach(required->inUse.remove(required)); runner.after(this); } boolean isEmpty() { return pendingAddition.isEmpty() && beingExecuted.isEmpty(); } void killAll() { pendingAddition.clear(); for (int i = 0; i < beingExecuted.size(); i++) { CommandRunner c = beingExecuted.poll(); c.cancel(); c.step(0); } } }