/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.component.execution.internal; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.Semaphore; import org.apache.commons.logging.LogFactory; import de.rcenvironment.core.component.api.DistributedComponentKnowledge; import de.rcenvironment.core.component.api.DistributedComponentKnowledgeService; import de.rcenvironment.core.component.model.api.ComponentInstallation; import de.rcenvironment.core.component.spi.DistributedComponentKnowledgeListener; import de.rcenvironment.core.toolkitbridge.transitional.ConcurrencyUtils; import de.rcenvironment.core.utils.common.StringUtils; import de.rcenvironment.toolkit.modules.concurrency.api.TaskDescription; /** * Implementation of {@link ComponentExecutionPermitsService}. * * @author Doreen Seider */ public class ComponentExecutionPermitsServiceImpl implements ComponentExecutionPermitsService, DistributedComponentKnowledgeListener { private DistributedComponentKnowledgeService componentKnowledgeService; // component id -> semaphore object private Map<String, ResizableSemaphore> semaphores = null; @Override public void onDistributedComponentKnowledgeChanged(DistributedComponentKnowledge newState) { updateSemaphores(newState); } private synchronized void updateSemaphores(DistributedComponentKnowledge componentKnowledge) { if (semaphores == null) { semaphores = Collections.synchronizedMap(new HashMap<String, ResizableSemaphore>()); } for (ComponentInstallation compInstallation : componentKnowledge.getAllInstallations()) { if (compInstallation.getMaximumCountOfParallelInstances() != null) { if (!semaphores.containsKey(compInstallation.getInstallationId())) { semaphores.put(compInstallation.getInstallationId(), new ResizableSemaphore(compInstallation.getMaximumCountOfParallelInstances())); } else { semaphores.get(compInstallation.getInstallationId()) .updateMaximumPermits(compInstallation.getMaximumCountOfParallelInstances()); } } } } @Override public synchronized Future<Boolean> acquire(final String componentIdentifier, final String executionIdentifier) { if (semaphores == null) { updateSemaphores(componentKnowledgeService.getCurrentComponentKnowledge()); } final ResizableSemaphore semaphore = semaphores.get(componentIdentifier); return ConcurrencyUtils.getAsyncTaskService().submit(new Callable<Boolean>() { @TaskDescription("Acquire component execution permit") @Override public Boolean call() throws Exception { boolean aquired = false; if (semaphore != null) { try { semaphore.acquire(); aquired = true; } catch (InterruptedException e) { LogFactory.getLog(getClass()) .debug(StringUtils.format("Interupted while waiting for execution permit for component '%s' - %s", componentIdentifier, executionIdentifier)); } } return aquired; } }, StringUtils.format("Waiting for execution permit for component '%s' - %s", componentIdentifier, executionIdentifier)); } @Override public synchronized void release(final String componentIdentifier) { if (semaphores == null) { updateSemaphores(componentKnowledgeService.getCurrentComponentKnowledge()); } if (semaphores.containsKey(componentIdentifier)) { semaphores.get(componentIdentifier).release(); } } /** * Resizable {@link Semaphore} that allows to increase and decrease maximum permits. * * @author Doreen Seider */ private class ResizableSemaphore { private static final int MINUS_ONE = -1; private final ReducableSemaphore semaphore; private int maxPermits; protected ResizableSemaphore(int maxPermits) { semaphore = new ReducableSemaphore(maxPermits); this.maxPermits = maxPermits; } protected void acquire() throws InterruptedException { semaphore.acquire(); } protected synchronized void release() { if (semaphore.availablePermits() < maxPermits) { semaphore.release(); } } protected void updateMaximumPermits(int newMaxPermits) { int diff = maxPermits - newMaxPermits; if (diff < 0) { semaphore.release(diff * MINUS_ONE); } else if (diff > 0) { semaphore.reducePermits(diff); } maxPermits = newMaxPermits; } } /** * {@link Semaphore} that allows to decrease permits. */ private class ReducableSemaphore extends Semaphore { private static final long serialVersionUID = 5372099537410330875L; protected ReducableSemaphore(int maxPermits) { super(maxPermits, true); } @Override protected void reducePermits(int reduction) { super.reducePermits(reduction); } } protected void bindDistributedComponentKnowledgeService(DistributedComponentKnowledgeService service) { componentKnowledgeService = service; } }