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.concurrent.ConcurrentHashMap; 022import java.util.concurrent.ConcurrentMap; 023import java.util.concurrent.atomic.AtomicInteger; 024 025import org.eclipse.aether.named.NamedLockFactory; 026import org.slf4j.Logger; 027import org.slf4j.LoggerFactory; 028 029import static java.util.Objects.requireNonNull; 030 031/** 032 * Support class for {@link NamedLockFactory} implementations providing reference counting. 033 */ 034public abstract class NamedLockFactorySupport implements NamedLockFactory { 035 protected final Logger logger = LoggerFactory.getLogger(getClass()); 036 037 private final ConcurrentMap<String, NamedLockHolder> locks; 038 039 public NamedLockFactorySupport() { 040 this.locks = new ConcurrentHashMap<>(); 041 } 042 043 @Override 044 public NamedLockSupport getLock(final String name) { 045 return locks.compute(name, (k, v) -> { 046 if (v == null) { 047 v = new NamedLockHolder(createLock(k)); 048 } 049 v.incRef(); 050 return v; 051 }) 052 .namedLock; 053 } 054 055 @Override 056 public void shutdown() { 057 // override if needed 058 } 059 060 public void closeLock(final String name) { 061 locks.compute(name, (k, v) -> { 062 if (v != null && v.decRef() == 0) { 063 destroyLock(v.namedLock.name()); 064 return null; 065 } 066 return v; 067 }); 068 } 069 070 /** 071 * Implementations shall create and return {@link NamedLockSupport} for given {@code name}, this method must never 072 * return {@code null}. 073 */ 074 protected abstract NamedLockSupport createLock(String name); 075 076 /** 077 * Implementation may override this (empty) method to perform some sort of implementation specific cleanup for 078 * given lock name. Invoked when reference count for given name drops to zero and named lock was removed. 079 */ 080 protected void destroyLock(final String name) { 081 // override if needed 082 } 083 084 private static final class NamedLockHolder { 085 private final NamedLockSupport namedLock; 086 087 private final AtomicInteger referenceCount; 088 089 private NamedLockHolder(final NamedLockSupport namedLock) { 090 this.namedLock = requireNonNull(namedLock); 091 this.referenceCount = new AtomicInteger(0); 092 } 093 094 private int incRef() { 095 return referenceCount.incrementAndGet(); 096 } 097 098 private int decRef() { 099 return referenceCount.decrementAndGet(); 100 } 101 102 @Override 103 public String toString() { 104 return "[refCount=" + referenceCount.get() + ", lock=" + namedLock + "]"; 105 } 106 } 107}