001package org.eclipse.aether.named.hazelcast;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import com.hazelcast.core.HazelcastInstance;
023import com.hazelcast.cp.ISemaphore;
024import org.eclipse.aether.named.support.AdaptedSemaphoreNamedLock;
025import org.eclipse.aether.named.support.AdaptedSemaphoreNamedLock.AdaptedSemaphore;
026import org.eclipse.aether.named.support.NamedLockFactorySupport;
027
028import java.util.concurrent.ConcurrentHashMap;
029import java.util.concurrent.ConcurrentMap;
030import java.util.concurrent.TimeUnit;
031import java.util.function.BiFunction;
032
033/**
034 * Factory of {@link AdaptedSemaphoreNamedLock} instances using adapted Hazelcast {@link ISemaphore}. This class may
035 * use {@link HazelcastInstance} backed by Hazelcast Server or Hazelcast Client.
036 */
037public class HazelcastSemaphoreNamedLockFactory
038    extends NamedLockFactorySupport
039{
040    protected static final String NAME_PREFIX = "maven:resolver:";
041
042    private final HazelcastInstance hazelcastInstance;
043
044    private final BiFunction<HazelcastInstance, String, ISemaphore> semaphoreFunction;
045
046    private final boolean destroySemaphore;
047
048    private final boolean manageHazelcast;
049
050    private final ConcurrentMap<String, ISemaphore> semaphores;
051
052    public HazelcastSemaphoreNamedLockFactory(
053        final HazelcastInstance hazelcastInstance,
054        final BiFunction<HazelcastInstance, String, ISemaphore> semaphoreFunction,
055        final boolean destroySemaphore,
056        final boolean manageHazelcast
057    )
058    {
059        this.hazelcastInstance = hazelcastInstance;
060        this.semaphoreFunction = semaphoreFunction;
061        this.destroySemaphore = destroySemaphore;
062        this.manageHazelcast = manageHazelcast;
063        this.semaphores = new ConcurrentHashMap<>();
064    }
065
066    @Override
067    protected AdaptedSemaphoreNamedLock createLock( final String name )
068    {
069        ISemaphore semaphore = semaphores.computeIfAbsent( name, k ->
070        {
071            ISemaphore result = semaphoreFunction.apply( hazelcastInstance, k );
072            result.init( Integer.MAX_VALUE );
073            return result;
074        } );
075        return new AdaptedSemaphoreNamedLock( name, this, new HazelcastSemaphore( semaphore ) );
076    }
077
078    @Override
079    public void shutdown()
080    {
081        if ( manageHazelcast )
082        {
083            hazelcastInstance.shutdown();
084        }
085    }
086
087    @Override
088    protected void destroyLock( final String name )
089    {
090        ISemaphore semaphore = semaphores.remove( name );
091        if ( destroySemaphore )
092        {
093            if ( semaphore == null )
094            {
095                throw new IllegalStateException( "Semaphore expected but does not exist: " + name );
096            }
097            semaphore.destroy();
098        }
099    }
100
101    private static final class HazelcastSemaphore implements AdaptedSemaphore
102    {
103        private final ISemaphore semaphore;
104
105        private HazelcastSemaphore( final ISemaphore semaphore )
106        {
107            this.semaphore = semaphore;
108        }
109
110        @Override
111        public boolean tryAcquire( final int perms, final long time, final TimeUnit unit )
112            throws InterruptedException
113        {
114            return semaphore.tryAcquire( perms, time, unit );
115        }
116
117        @Override
118        public void release( final int perms )
119        {
120            semaphore.release( perms );
121        }
122    }
123}