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.Collections; 023import java.util.Deque; 024import java.util.Map; 025import java.util.concurrent.ConcurrentHashMap; 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 * Support class for {@link NamedLock} implementations providing reference counting. 035 */ 036public abstract class NamedLockSupport implements NamedLock { 037 protected final Logger logger = LoggerFactory.getLogger(getClass()); 038 039 private final NamedLockKey key; 040 041 private final NamedLockFactorySupport factory; 042 043 private final ConcurrentHashMap<Thread, Deque<String>> diagnosticState; // non-null only if diag enabled 044 045 public NamedLockSupport(final NamedLockKey key, final NamedLockFactorySupport factory) { 046 this.key = key; 047 this.factory = factory; 048 this.diagnosticState = factory.isDiagnosticEnabled() ? new ConcurrentHashMap<>() : null; 049 } 050 051 @Override 052 public NamedLockKey key() { 053 return key; 054 } 055 056 @Override 057 public boolean lockShared(long time, TimeUnit unit) throws InterruptedException { 058 Deque<String> steps = null; 059 if (diagnosticState != null) { 060 steps = diagnosticState.computeIfAbsent(Thread.currentThread(), k -> new ArrayDeque<>()); 061 } 062 if (steps != null) { 063 steps.push("wait-shared"); 064 } 065 boolean result = doLockShared(time, unit); 066 if (steps != null) { 067 steps.pop(); 068 if (result) { 069 steps.push("shared"); 070 } 071 } 072 return result; 073 } 074 075 protected abstract boolean doLockShared(long time, TimeUnit unit) throws InterruptedException; 076 077 @Override 078 public boolean lockExclusively(long time, TimeUnit unit) throws InterruptedException { 079 Deque<String> steps = null; 080 if (diagnosticState != null) { 081 steps = diagnosticState.computeIfAbsent(Thread.currentThread(), k -> new ArrayDeque<>()); 082 } 083 if (steps != null) { 084 steps.push("wait-exclusive"); 085 } 086 boolean result = doLockExclusively(time, unit); 087 if (steps != null) { 088 steps.pop(); 089 if (result) { 090 steps.push("exclusive"); 091 } 092 } 093 return result; 094 } 095 096 protected abstract boolean doLockExclusively(long time, TimeUnit unit) throws InterruptedException; 097 098 @Override 099 public void unlock() { 100 doUnlock(); 101 if (diagnosticState != null) { 102 diagnosticState 103 .computeIfAbsent(Thread.currentThread(), k -> new ArrayDeque<>()) 104 .pop(); 105 } 106 } 107 108 protected abstract void doUnlock(); 109 110 @Override 111 public final void close() { 112 doClose(); 113 } 114 115 protected void doClose() { 116 factory.closeLock(key); 117 } 118 119 /** 120 * Returns the diagnostic state (if collected) or empty map, never {@code null}. 121 * 122 * @since 1.9.11 123 */ 124 public Map<Thread, Deque<String>> diagnosticState() { 125 if (diagnosticState != null) { 126 return diagnosticState; 127 } else { 128 return Collections.emptyMap(); 129 } 130 } 131 132 @Override 133 public String toString() { 134 return getClass().getSimpleName() + "{" + "key='" + key + '\'' + '}'; 135 } 136}