001/* 002 * ============================================================================ 003 * Copyright © 2002-2024 by Thomas Thrien. 004 * All Rights Reserved. 005 * ============================================================================ 006 * 007 * Licensed to the public under the agreements of the GNU Lesser General Public 008 * License, version 3.0 (the "License"). You may obtain a copy of the License at 009 * 010 * http://www.gnu.org/licenses/lgpl.html 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 015 * License for the specific language governing permissions and limitations 016 * under the License. 017 */ 018 019package org.tquadrat.foundation.lang; 020 021import static org.apiguardian.api.API.Status.STABLE; 022 023import java.io.Serial; 024import java.util.Optional; 025import java.util.concurrent.locks.Condition; 026import java.util.concurrent.locks.Lock; 027 028import org.apiguardian.api.API; 029import org.tquadrat.foundation.annotation.ClassVersion; 030import org.tquadrat.foundation.lang.internal.AutoLockImpl; 031 032/** 033 * <p>{@summary A wrapper for locks that supports the 034 * {@code try-with-resources} feature of Java 7.}</p> 035 * <p>Instead of</p> 036 * <div class="source-container"><pre> m_Lock.lock(); 037 * try 038 * { 039 * … 040 * } 041 * finally 042 * { 043 * m_Lock.unlock(); 044 * }</pre></div> 045 * <p>you can write now</p> 046 * <div class="source-container"><pre> private final AutoLock m_AutoLock = AutoLock.of(); 047 * 048 * … 049 * 050 * try( final var ignored = m_AutoLock.lock() ) 051 * { 052 * … 053 * }</pre></div> 054 * <p>The creation of the local reference to the wrapper object means some 055 * overhead but in very most scenarios this is negligible.</p> 056 * <p>{@code AutoLock} will only expose the methods 057 * {@link #lock()} 058 * and 059 * {@link #lockInterruptibly()} 060 * of the interface 061 * {@link java.util.concurrent.locks.Lock Lock}, 062 * but with a return value. Exposing other methods is not reasonable.</p> 063 * <p>Calling 064 * {@link #close()} 065 * on the {@code AutoLock} instance or 066 * {@link Lock#unlock()} 067 * on the wrapped {@code Lock} object inside the {@code try} block may cause 068 * unpredictable effects.</p> 069 * 070 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 071 * @version $Id: AutoLock.java 1097 2024-02-06 20:10:12Z tquadrat $ 072 * @since 0.1.0 073 * 074 * @see java.util.concurrent.locks.Lock 075 * 076 * @UMLGraph.link 077 */ 078@ClassVersion( sourceVersion = "$Id: AutoLock.java 1097 2024-02-06 20:10:12Z tquadrat $" ) 079@API( status = STABLE, since = "0.1.0" ) 080public sealed interface AutoLock extends AutoCloseable 081 permits org.tquadrat.foundation.lang.internal.AutoLockImpl 082{ 083 /*---------------*\ 084 ====** Inner Classes **==================================================== 085 \*---------------*/ 086 /** 087 * <p>{@summary This exception is thrown when an operation fails.} The 088 * 089 * @version $Id: AutoLock.java 1097 2024-02-06 20:10:12Z tquadrat $ 090 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 091 * @UMLGraph.link 092 * @since 0.1.0 093 */ 094 @SuppressWarnings( "InnerClassOfInterface" ) 095 @ClassVersion( sourceVersion = "$Id: AutoLock.java 1097 2024-02-06 20:10:12Z tquadrat $" ) 096 @API( status = STABLE, since = "0.1.0" ) 097 public static final class ExecutionFailedException extends RuntimeException 098 { 099 /*------------------------*\ 100 ====** Static Initialisations **======================================= 101 \*------------------------*/ 102 /** 103 * The serial version UID for objects of this class: {@value}. 104 * 105 * @hidden 106 */ 107 @Serial 108 private static final long serialVersionUID = 1L; 109 110 /*--------------*\ 111 ====** Constructors **================================================= 112 \*--------------*/ 113 /** 114 * Creates a new instance of {@code ExecutionFailedException} from the 115 * cause of the failure. 116 * 117 * @param cause The failure cause. 118 */ 119 public ExecutionFailedException( final Throwable cause ) { super( cause ); } 120 } // class ExecutionFailedException 121 122 /*---------*\ 123 ====** Methods **========================================================== 124 \*---------*/ 125 /** 126 * {@inheritDoc} 127 */ 128 @Override 129 public void close(); 130 131 /** 132 * Evaluates the given 133 * {@link Constraint} 134 * after obtaining the lock, and returns its result. 135 * 136 * @param constraint The constraint 137 * @return The evaluation result. 138 * @throws ExecutionFailedException The evaluation failed for some 139 * reason. 140 */ 141 @SuppressWarnings( "BooleanMethodNameMustStartWithQuestion" ) 142 public boolean evaluate( final Constraint constraint ) throws ExecutionFailedException; 143 144 /** 145 * Executes the given action after obtaining the lock. 146 * 147 * @param action The action. 148 * @throws ExecutionFailedException The action failed for some reason. 149 */ 150 public void execute( final Action action ) throws ExecutionFailedException; 151 152 /** 153 * Executes the given operation after obtaining the lock, and returns its 154 * result. 155 * 156 * @param <R> The type of the operation's result. 157 * @param operation The operation. 158 * @return An instance of 159 * {@link Optional} 160 * that holds the result of the operation. 161 * @throws ExecutionFailedException The operation failed for some 162 * reason. 163 */ 164 public <R> Optional<R> execute( final Operation<? extends R> operation ) throws ExecutionFailedException; 165 166 /** 167 * Returns the wrapped lock. 168 * 169 * @return The wrapped lock. 170 */ 171 public Lock getWrappedLockInstance(); 172 173 /** 174 * Calls 175 * {@link java.util.concurrent.locks.Lock#lock() lock()} 176 * on the wrapped 177 * {@link java.util.concurrent.locks.Lock} 178 * instance. 179 * 180 * @return The reference to this {@code AutoLock} instance. 181 */ 182 public AutoLock lock(); 183 184 /** 185 * Calls 186 * {@link java.util.concurrent.locks.Lock#lockInterruptibly() lockInterruptibly()} 187 * on the wrapped 188 * {@link java.util.concurrent.locks.Lock} 189 * instance. 190 * 191 * @return The reference to this {@code AutoLock} instance. 192 * @throws InterruptedException The current thread was interrupted while 193 * acquiring the lock (and interruption of lock acquisition is 194 * supported). 195 */ 196 public AutoLock lockInterruptibly() throws InterruptedException; 197 198 /** 199 * Returns a new 200 * {@link Condition} 201 * instance that is bound to the instance of 202 * {@link java.util.concurrent.locks.Lock} 203 * that is wrapped by this {@code AutoLock} instance. 204 * 205 * @return The new condition. 206 * @throws UnsupportedOperationException The wrapped lock's 207 * implementation does not support conditions. 208 * 209 * @see java.util.concurrent.locks.Lock#newCondition() 210 */ 211 public Condition newCondition(); 212 213 /** 214 * Creates a new {@code AutoLock} instance with an internal lock object. 215 * 216 * @return The new instance. 217 */ 218 @API( status = STABLE, since = "0.0.5" ) 219 public static AutoLock of() { return new AutoLockImpl(); } 220 221 /** 222 * Creates a new {@code AutoLock} instance from the given 223 * {@link Lock} 224 * instance. 225 * 226 * @param lock The wrapped lock. 227 * @return The new instance. 228 */ 229 @API( status = STABLE, since = "0.0.5" ) 230 public static AutoLock of( final Lock lock ) { return new AutoLockImpl( lock ); } 231} 232// interface AutoLock 233 234/* 235 * End of File 236 */