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 try { 070 for (NamedLock namedLock : locks.values()) { 071 LOGGER.trace("{}: Acquiring {} lock for '{}'", key().name(), lockKind, namedLock.key()); 072 073 boolean locked; 074 if (shared) { 075 locked = namedLock.lockShared(time, timeUnit); 076 } else { 077 locked = namedLock.lockExclusively(time, timeUnit); 078 } 079 080 if (!locked) { 081 LOGGER.trace( 082 "{}: Failed to acquire {} lock for '{}' in {}", 083 key().name(), 084 lockKind, 085 namedLock.key(), 086 timeStr); 087 088 unlockAll(step); 089 return false; 090 } else { 091 step.push(namedLock); 092 } 093 } 094 } catch (Throwable t) { 095 unlockAll(step); 096 throw t; 097 } 098 steps.push(step); 099 return true; 100 } 101 102 @Override 103 protected void doUnlock() { 104 unlockAll(steps.pop()); 105 } 106 107 @Override 108 protected void doClose() { 109 locks.values().forEach(NamedLock::close); 110 } 111 112 private void unlockAll(final ArrayDeque<NamedLock> locks) { 113 if (locks.isEmpty()) { 114 return; 115 } 116 117 // Release locks in reverse locking order 118 while (!locks.isEmpty()) { 119 NamedLock namedLock = locks.pop(); 120 LOGGER.trace("{}: Releasing lock for '{}'", key().name(), namedLock.key()); 121 namedLock.unlock(); 122 } 123 } 124}