001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.named.redisson; 020 021import javax.inject.Named; 022import javax.inject.Singleton; 023 024import java.util.concurrent.ConcurrentHashMap; 025import java.util.concurrent.ConcurrentMap; 026import java.util.concurrent.TimeUnit; 027 028import org.eclipse.aether.named.NamedLock; 029import org.eclipse.aether.named.NamedLockKey; 030import org.eclipse.aether.named.support.AdaptedSemaphoreNamedLock; 031import org.redisson.api.RSemaphore; 032 033/** 034 * Provider of {@link RedissonSemaphoreNamedLockFactory} using Redisson and {@link org.redisson.api.RSemaphore}. 035 */ 036@Singleton 037@Named(RedissonSemaphoreNamedLockFactory.NAME) 038public class RedissonSemaphoreNamedLockFactory extends RedissonNamedLockFactorySupport { 039 public static final String NAME = "semaphore-redisson"; 040 041 private static final String TYPED_NAME_PREFIX = NAME_PREFIX + NAME + ":"; 042 043 private final ConcurrentMap<NamedLockKey, RSemaphore> semaphores; 044 045 public RedissonSemaphoreNamedLockFactory() { 046 this.semaphores = new ConcurrentHashMap<>(); 047 } 048 049 @Override 050 protected AdaptedSemaphoreNamedLock createLock(final NamedLockKey key) { 051 RSemaphore semaphore = semaphores.computeIfAbsent(key, k -> { 052 RSemaphore result = redissonClient.getSemaphore(TYPED_NAME_PREFIX + k.name()); 053 result.trySetPermits(Integer.MAX_VALUE); 054 return result; 055 }); 056 return new AdaptedSemaphoreNamedLock(key, this, new RedissonSemaphore(semaphore)); 057 } 058 059 @Override 060 protected void destroyLock(final NamedLock namedLock) { 061 if (namedLock instanceof AdaptedSemaphoreNamedLock) { 062 final NamedLockKey key = namedLock.key(); 063 RSemaphore semaphore = semaphores.remove(key); 064 if (semaphore == null) { 065 throw new IllegalStateException("Semaphore expected, but does not exist: " + key); 066 } 067 /* There is no reasonable way to destroy the semaphore in Redis because we cannot know 068 * when the last process has stopped using it. 069 */ 070 } 071 } 072 073 private static final class RedissonSemaphore implements AdaptedSemaphoreNamedLock.AdaptedSemaphore { 074 private final RSemaphore semaphore; 075 076 private RedissonSemaphore(final RSemaphore semaphore) { 077 this.semaphore = semaphore; 078 } 079 080 @Override 081 public boolean tryAcquire(final int perms, final long time, final TimeUnit unit) throws InterruptedException { 082 return semaphore.tryAcquire(perms, time, unit); 083 } 084 085 @Override 086 public void release(final int perms) { 087 semaphore.release(perms); 088 } 089 } 090}