1 /* 2 * junixsocket 3 * 4 * Copyright 2009-2024 Christian Kohlschütter 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.newsclub.net.unix; 19 20 import java.io.Closeable; 21 import java.io.IOException; 22 import java.lang.ref.Cleaner; 23 24 import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement; 25 26 /** 27 * This wrapper (along with the Java 8-specific counterpart in src/main/java8) allows us to 28 * implement cleanup logic for objects that are garbage-collectable/no longer reachable. 29 * 30 * <p> 31 * Usage: 32 * <ol> 33 * <li>Create a subclass of CleanableState and attach it as a private field to the object you want 34 * to be cleaned up. You may call that field {@code cleanableState}.</li> 35 * <li>Define all resources that need to be cleaned up in this subclass (instead of the observed 36 * object itself).</li> 37 * <li>Make sure to not refer the observed object instance itself, as that will create a reference 38 * cycle and prevent proper cleanup.</li> 39 * <li>Implement the {@link #doClean()} method to perform all the necessary cleanup steps.</li> 40 * <li>If the observed class implements {@code close()}, it's a good practice to have it just call 41 * {@code cleanableState.runCleaner()}.</li> 42 * </ol> 43 * </p> 44 * <p> 45 * Implementation details: 46 * <ul> 47 * <li>In Java 9 or later, {@link Cleaner} is used under the hood.</li> 48 * <li>In Java 8 or earlier, {@link #finalize()} calls {@link #doClean()} directly.</li> 49 * </ul> 50 * </p> 51 * 52 * @author Christian Kohlschütter 53 */ 54 @IgnoreJRERequirement // see src/main/java8 55 abstract class CleanableState implements Closeable { 56 private static final Cleaner CLEANER = Cleaner.create(); 57 private final Cleaner.Cleanable cleanable; 58 59 /** 60 * Creates a state object to be used as an implementation detail of the specified observed 61 * instance. 62 * 63 * @param observed The observed instance (the outer class referencing this 64 * {@link CleanableState}). 65 */ 66 protected CleanableState(Object observed) { 67 this.cleanable = CLEANER.register(observed, () -> doClean()); // NOPMD.LambdaCanBeMethodReference 68 // (Retrolambda) 69 } 70 71 /** 72 * Explicitly the cleanup code defined in {@link #doClean()}. This is best be called from a 73 * {@code close()} method in the observed class. 74 */ 75 public final void runCleaner() { 76 cleanable.clean(); 77 } 78 79 /** 80 * Performs the actual cleanup. 81 */ 82 protected abstract void doClean(); 83 84 @Override 85 public final void close() throws IOException { 86 runCleaner(); 87 } 88 }