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