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.support; 020 021import java.util.ArrayDeque; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.LinkedHashMap; 025import java.util.Map; 026import java.util.concurrent.TimeUnit; 027 028import org.eclipse.aether.named.NamedLock; 029import org.eclipse.aether.named.NamedLockKey; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033/** 034 * Implementation of composite lock when "composition" is needed for locks that are naturally mapped as 1:1 name 035 * vs some backing implementation. Instances of these locks are "unique per call" and are not ref counted. 036 * 037 * @since 2.0.0 038 */ 039public final class CompositeNamedLock extends NamedLockSupport { 040 private static final Logger LOGGER = LoggerFactory.getLogger(CompositeNamedLock.class); 041 042 private final Map<NamedLockKey, NamedLock> locks; 043 044 private final ArrayDeque<ArrayDeque<NamedLock>> steps = new ArrayDeque<>(); 045 046 public CompositeNamedLock(NamedLockKey key, NamedLockFactorySupport factory, Collection<NamedLock> namedLocks) { 047 super(key, factory); 048 LinkedHashMap<NamedLockKey, NamedLock> map = new LinkedHashMap<>(); 049 namedLocks.forEach(l -> map.put(l.key(), l)); 050 this.locks = Collections.unmodifiableMap(map); 051 } 052 053 @Override 054 protected boolean doLockShared(long time, TimeUnit unit) throws InterruptedException { 055 return lock(time, unit, true); 056 } 057 058 @Override 059 protected boolean doLockExclusively(long time, TimeUnit unit) throws InterruptedException { 060 return lock(time, unit, false); 061 } 062 063 private boolean lock(long time, TimeUnit timeUnit, boolean shared) throws InterruptedException { 064 final ArrayDeque<NamedLock> step = new ArrayDeque<>(locks.size()); 065 final String timeStr = time + " " + timeUnit; 066 final String lockKind = shared ? "shared" : "exclusive"; 067 LOGGER.trace( 068 "{}: Need {} {} lock(s) of {} in {}", key().name(), locks.size(), lockKind, key().resources(), timeStr); 069 for (NamedLock namedLock : locks.values()) { 070 LOGGER.trace("{}: Acquiring {} lock for '{}'", key().name(), lockKind, namedLock.key()); 071 072 boolean locked; 073 if (shared) { 074 locked = namedLock.lockShared(time, timeUnit); 075 } else { 076 locked = namedLock.lockExclusively(time, timeUnit); 077 } 078 079 if (!locked) { 080 LOGGER.trace( 081 "{}: Failed to acquire {} lock for '{}' in {}", 082 key().name(), 083 lockKind, 084 namedLock.key(), 085 timeStr); 086 087 unlockAll(step); 088 break; 089 } else { 090 step.push(namedLock); 091 } 092 } 093 if (step.size() == locks.size()) { 094 steps.push(step); 095 return true; 096 } 097 unlockAll(step); 098 return false; 099 } 100 101 @Override 102 protected void doUnlock() { 103 unlockAll(steps.pop()); 104 } 105 106 @Override 107 protected void doClose() { 108 locks.values().forEach(NamedLock::close); 109 } 110 111 private void unlockAll(final ArrayDeque<NamedLock> locks) { 112 if (locks.isEmpty()) { 113 return; 114 } 115 116 // Release locks in reverse locking order 117 while (!locks.isEmpty()) { 118 NamedLock namedLock = locks.pop(); 119 LOGGER.trace("{}: Releasing lock for '{}'", key().name(), namedLock.key()); 120 namedLock.unlock(); 121 } 122 } 123}