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.hazelcast; 020 021import java.nio.file.Files; 022import java.nio.file.Paths; 023import java.util.concurrent.ConcurrentHashMap; 024import java.util.concurrent.ConcurrentMap; 025import java.util.concurrent.TimeUnit; 026 027import com.hazelcast.core.HazelcastInstance; 028import com.hazelcast.cp.ISemaphore; 029import org.eclipse.aether.named.NamedLock; 030import org.eclipse.aether.named.NamedLockKey; 031import org.eclipse.aether.named.support.AdaptedSemaphoreNamedLock; 032import org.eclipse.aether.named.support.AdaptedSemaphoreNamedLock.AdaptedSemaphore; 033import org.eclipse.aether.named.support.NamedLockFactorySupport; 034 035import static java.util.Objects.requireNonNull; 036 037/** 038 * Factory of {@link AdaptedSemaphoreNamedLock} instances, using adapted Hazelcast {@link ISemaphore}. It delegates 039 * most the work to {@link HazelcastSemaphoreProvider} and this class just adapts the returned semaphore to named lock 040 * and caches {@link ISemaphore} instances, as recommended by Hazelcast. 041 * 042 * @deprecated Hazelcast support will be dropped. 043 */ 044@Deprecated 045public class HazelcastSemaphoreNamedLockFactory extends NamedLockFactorySupport { 046 protected final HazelcastInstance hazelcastInstance; 047 048 protected final boolean manageHazelcast; 049 050 private final HazelcastSemaphoreProvider hazelcastSemaphoreProvider; 051 052 private final ConcurrentMap<NamedLockKey, ISemaphore> semaphores; 053 054 public HazelcastSemaphoreNamedLockFactory( 055 final HazelcastInstance hazelcastInstance, 056 final boolean manageHazelcast, 057 final HazelcastSemaphoreProvider hazelcastSemaphoreProvider) { 058 this.hazelcastInstance = requireNonNull(hazelcastInstance); 059 this.manageHazelcast = manageHazelcast; 060 this.hazelcastSemaphoreProvider = requireNonNull(hazelcastSemaphoreProvider); 061 this.semaphores = new ConcurrentHashMap<>(); 062 } 063 064 /** 065 * Guard used by the default constructors of subclasses before they create a Hazelcast member or client via 066 * standard Hazelcast configuration discovery: refuses to proceed when no explicit operator-provided 067 * configuration is discoverable. Without one, Hazelcast falls back to its built-in defaults (default cluster 068 * name, auto-discovery join, no authentication or TLS in open-source Hazelcast), which lets any peer able to 069 * reach the network segment join the cluster and release the semaphore permits that guard local repository 070 * writes. 071 * 072 * @param configSystemProperty the Hazelcast system property naming an explicit configuration file 073 * @param classLoader the class loader to probe for configuration resources 074 * @param configResourceNames configuration file names probed on the classpath and in the working directory 075 * @throws IllegalStateException if no explicit configuration is discoverable 076 */ 077 static void requireExplicitHazelcastConfig( 078 final String configSystemProperty, final ClassLoader classLoader, final String... configResourceNames) { 079 if (System.getProperty(configSystemProperty) != null) { 080 return; 081 } 082 for (String configResourceName : configResourceNames) { 083 if (classLoader.getResource(configResourceName) != null 084 || Files.isRegularFile(Paths.get(configResourceName))) { 085 return; 086 } 087 } 088 throw new IllegalStateException( 089 "Refusing to create a Hazelcast instance from built-in defaults (default cluster name," 090 + " auto-discovery join, no authentication): distributed lock state guarding local" 091 + " repository writes would be modifiable by unauthenticated network peers. Provide an" 092 + " explicit Hazelcast configuration that secures or isolates the cluster, via the '" 093 + configSystemProperty + "' system property or one of " 094 + String.join(", ", configResourceNames) 095 + " on the classpath or in the working directory."); 096 } 097 098 @Override 099 protected AdaptedSemaphoreNamedLock createLock(final NamedLockKey key) { 100 ISemaphore semaphore = semaphores.computeIfAbsent( 101 key, k -> hazelcastSemaphoreProvider.acquireSemaphore(hazelcastInstance, key)); 102 return new AdaptedSemaphoreNamedLock(key, this, new HazelcastSemaphore(semaphore)); 103 } 104 105 @Override 106 protected void destroyLock(final NamedLock namedLock) { 107 if (namedLock instanceof AdaptedSemaphoreNamedLock) { 108 final NamedLockKey key = namedLock.key(); 109 hazelcastSemaphoreProvider.releaseSemaphore(hazelcastInstance, key, semaphores.remove(key)); 110 } 111 } 112 113 @Override 114 protected void doShutdown() { 115 if (manageHazelcast) { 116 hazelcastInstance.shutdown(); 117 } 118 } 119 120 private static final class HazelcastSemaphore implements AdaptedSemaphore { 121 private final ISemaphore semaphore; 122 123 private HazelcastSemaphore(final ISemaphore semaphore) { 124 this.semaphore = semaphore; 125 } 126 127 @Override 128 public boolean tryAcquire(final int perms, final long time, final TimeUnit unit) throws InterruptedException { 129 return semaphore.tryAcquire(perms, time, unit); 130 } 131 132 @Override 133 public void release(final int perms) { 134 semaphore.release(perms); 135 } 136 } 137}