/** * 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 org.apache.ambari.server.orm; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.ambari.annotations.TransactionalLock.LockArea; import org.apache.ambari.server.configuration.Configuration; import com.google.inject.Inject; import com.google.inject.Singleton; import com.google.inject.persist.Transactional; /** * The {@link TransactionalLocks} class is used to manage the locks associated * with each {@link LockArea}. It's a singlegon that shoudl always be injected. */ @Singleton public class TransactionalLocks { /** * Used to lookup whether {@link LockArea}s are enabled. */ private final Configuration m_configuration; /** * Manages the locks for each class which uses the {@link Transactional} * annotation. */ private final ConcurrentHashMap<LockArea, ReadWriteLock> m_locks; /** * Constructor. * */ @Inject private TransactionalLocks(Configuration configuration) { m_configuration = configuration; m_locks = new ConcurrentHashMap<>(); for (LockArea lockArea : LockArea.values()) { final ReadWriteLock lock; if (lockArea.isEnabled(m_configuration)) { lock = new ReentrantReadWriteLock(true); } else { lock = new NoOperationReadWriteLock(); } m_locks.put(lockArea, lock); } } /** * Gets a lock for the specified lock area. There is a 1:1 relationship * between a lock area and a lock. * <p/> * If the {@link LockArea} is not enabled, then this will return an empty * {@link Lock} implementation which doesn't actually lock anything. * * @param lockArea * the lock area to get the lock for (not {@code null}). * @return the lock to use for the specified lock area (never {@code null}). */ public ReadWriteLock getLock(LockArea lockArea) { return m_locks.get(lockArea); } /** * A dummy implementation of a {@link ReadWriteLock} that returns locks which * only NOOP. This is used for cases where dependant code doesn't want to * {@code if/else} all over the place. */ private final static class NoOperationReadWriteLock implements ReadWriteLock { private final Lock m_readLock = new NoOperationLock(); private final Lock m_writeLock = new NoOperationLock(); /** * {@inheritDoc} */ @Override public Lock readLock() { return m_readLock; } /** * {@inheritDoc} */ @Override public Lock writeLock() { return m_writeLock; } } /** * A dummy implementation of a {@link Lock} that only NOOPs. This is used for * cases where dependant code doesn't want to {@code if/else} all over the * place. */ private final static class NoOperationLock implements Lock { /** * NOOP * <p/> * {@inheritDoc} */ @Override public void lock() { } /** * NOOP * <p/> * {@inheritDoc} */ @Override public void lockInterruptibly() throws InterruptedException { } /** * NOOP, returns {@code true} always. * <p/> * {@inheritDoc} */ @Override public boolean tryLock() { return true; } /** * NOOP, returns {@code true} always. * <p/> * {@inheritDoc} */ @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return true; } /** * NOOP * <p/> * {@inheritDoc} */ @Override public void unlock() { } @Override /** * NOOP * <p/> * {@inheritDoc} */ public Condition newCondition() { return null; } } }