package org.ovirt.engine.core.bll.network.macpool; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.annotation.PostConstruct; import javax.ejb.Singleton; import javax.ejb.Startup; import javax.inject.Inject; import org.ovirt.engine.core.bll.context.CommandContext; import org.ovirt.engine.core.common.businessentities.Cluster; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.ClusterDao; import org.ovirt.engine.core.dao.MacPoolDao; import org.ovirt.engine.core.utils.lock.AutoCloseableLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Singleton @Startup public class MacPoolPerCluster { @Inject private MacPoolDao macPoolDao; @Inject private ClusterDao clusterDao; @Inject private DecoratedMacPoolFactory decoratedMacPoolFactory; @Inject MacPoolFactory macPoolFactory; private static final Logger log = LoggerFactory.getLogger(MacPoolPerCluster.class); static final String UNABLE_TO_CREATE_MAC_POOL_IT_ALREADY_EXIST = "This MAC Pool already exist"; private final Map<Guid, MacPool> macPools = new HashMap<>(); private final ReentrantReadWriteLock lockObj = new ReentrantReadWriteLock(); //required by J2EE specification; session bean should have no-arg constructor. public MacPoolPerCluster() { } MacPoolPerCluster(MacPoolDao macPoolDao, ClusterDao clusterDao, MacPoolFactory macPoolFactory, DecoratedMacPoolFactory decoratedMacPoolFactory) { this.macPoolDao = macPoolDao; this.clusterDao = clusterDao; this.macPoolFactory = macPoolFactory; this.decoratedMacPoolFactory = decoratedMacPoolFactory; } @PostConstruct void initialize() { try { List<org.ovirt.engine.core.common.businessentities.MacPool> macPools = macPoolDao.getAll(); for (org.ovirt.engine.core.common.businessentities.MacPool macPool : macPools) { initializeMacPool(macPool); } log.info("Successfully initialized"); } catch (RuntimeException e) { log.error("Error initializing: {}", e.getMessage()); throw e; } } private void initializeMacPool(org.ovirt.engine.core.common.businessentities.MacPool macPool) { List<String> macsForMacPool = macPoolDao.getAllMacsForMacPool(macPool.getId()); final MacPool pool = createPoolInternal(macPool); log.debug("Initializing {} with macs: {}", pool, macsForMacPool); for (String mac : macsForMacPool) { pool.forceAddMac(mac); } } /** * @param clusterId id of cluster. * @return {@link ReadMacPool} instance that is transaction & compensation agnostic. */ public ReadMacPool getMacPoolForCluster(Guid clusterId) { return getMacPoolById(getMacPoolId(clusterId)); } /** * @param clusterId id of cluster. * @param commandContext command context, is used by {@link TransactionalMacPoolDecorator}. * @return {@link MacPool} instance to be used within transaction, compensation or scope without either. * @throws NullPointerException if commandContext is null */ public MacPool getMacPoolForCluster(Guid clusterId, CommandContext commandContext) { Objects.requireNonNull(commandContext); return getMacPoolById(getMacPoolId(clusterId), commandContext); } /** * Do not use this method from elsewhere, than from compensation mechanism. * @param macPoolId id of MacPool. * @return {@link MacPool instance} having given ID. */ public MacPool getMacPoolById(Guid macPoolId) { return getMacPoolById(macPoolId, Collections.emptyList()); } /** * @param macPoolId id of mac pool. * @return {@link MacPool} instance decorated by given decorators. */ private MacPool getMacPoolById(Guid macPoolId, List<MacPoolDecorator> decorators) { try (AutoCloseableLock lock = readLockResource()) { MacPool result = getMacPoolWithoutLocking(macPoolId, decorators); log.debug("Returning {} for requested id={}", result, macPoolId); return result; } } public MacPool getMacPoolById(Guid macPoolId, CommandContext commandContext) { return getMacPoolById(macPoolId, Collections.singletonList(new TransactionalMacPoolDecorator(commandContext))); } private Guid getMacPoolId(Guid clusterId) { final Cluster cluster = clusterDao.get(clusterId); return cluster == null ? null : cluster.getMacPoolId(); } private MacPool getMacPoolWithoutLocking(Guid macPoolId, List<MacPoolDecorator> decorators) { final MacPool poolById = macPools.get(macPoolId); if (poolById == null) { throw new IllegalStateException(createExceptionMessageMacPoolHavingIdDoesNotExist(macPoolId)); } return decoratedMacPoolFactory.createDecoratedPool(poolById, decorators); } /** * @param macPool pool definition */ public void createPool(org.ovirt.engine.core.common.businessentities.MacPool macPool) { try (AutoCloseableLock lock = writeLockResource()) { createPoolInternal(macPool); } } private MacPool createPoolInternal(org.ovirt.engine.core.common.businessentities.MacPool macPool) { if (macPools.containsKey(macPool.getId())) { throw new IllegalStateException(UNABLE_TO_CREATE_MAC_POOL_IT_ALREADY_EXIST); } log.debug("Creating new MacPool {}.", macPool); MacPool poolForScope = macPoolFactory.createMacPool(macPool); macPools.put(macPool.getId(), poolForScope); return poolForScope; } /** * @param macPool pool definition to re-init the pool */ public void modifyPool(org.ovirt.engine.core.common.businessentities.MacPool macPool) { try (AutoCloseableLock lock = writeLockResource()) { Guid macPoolId = macPool.getId(); if (!macPools.containsKey(macPoolId)) { throw new IllegalStateException(createExceptionMessageMacPoolHavingIdDoesNotExist(macPoolId)); } log.debug("Updating pool {}. (old will be deleted and new initialized from db entity)", macPool); removeWithoutLocking(macPoolId); initializeMacPool(macPool); } } public void removePool(Guid macPoolId) { try (AutoCloseableLock lock = writeLockResource()) { removeWithoutLocking(macPoolId); } } private void removeWithoutLocking(Guid macPoolId) { log.debug("Removing pool id=", macPoolId); macPools.remove(macPoolId); } String createExceptionMessageMacPoolHavingIdDoesNotExist(Guid macPoolId) { return String.format("Pool for id=\"%1$s\" does not exist", macPoolId); } protected AutoCloseableLock writeLockResource() { return new AutoCloseableLock(lockObj.writeLock()); } protected AutoCloseableLock readLockResource() { return new AutoCloseableLock(lockObj.readLock()); } }