/* * This file is part of ComputerCraft - http://www.computercraft.info * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http; import dan200.computercraft.shared.util.IoUtil; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import java.io.Closeable; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; /** * A holder for one or more resources, with a lifetime. */ public abstract class Resource> implements Closeable { private final AtomicBoolean closed = new AtomicBoolean( false ); private final ResourceGroup limiter; protected Resource( ResourceGroup limiter ) { this.limiter = limiter; } /** * Whether this resource is closed. * * @return Whether this resource is closed. */ public final boolean isClosed() { return closed.get(); } /** * Checks if this has been cancelled. If so, it'll clean up any * existing resources and cancel any pending futures. */ public final boolean checkClosed() { if( !closed.get() ) return false; dispose(); return true; } /** * Try to close the current resource. * * @return Whether this was successfully closed, or {@code false} if it has already been closed. */ protected final boolean tryClose() { if( closed.getAndSet( true ) ) return false; dispose(); return true; } /** * Clean up any pending resources * * Note, this may be called multiple times, and so should be thread-safe and * avoid any major side effects. */ protected void dispose() { @SuppressWarnings( "unchecked" ) T thisT = (T) this; limiter.release( thisT ); } /** * Create a {@link WeakReference} which will close {@code this} when collected. * * @param object The object to reference to * @return The weak reference. */ protected WeakReference createOwnerReference( R object ) { return new CloseReference<>( this, object ); } @Override public final void close() { tryClose(); } public boolean queue( Consumer task ) { @SuppressWarnings( "unchecked" ) T thisT = (T) this; return limiter.queue( thisT, () -> task.accept( thisT ) ); } protected static T closeCloseable( T closeable ) { if( closeable != null ) IoUtil.closeQuietly( closeable ); return null; } protected static ChannelFuture closeChannel( ChannelFuture future ) { if( future != null ) { future.cancel( false ); Channel channel = future.channel(); if( channel != null && channel.isOpen() ) channel.close(); } return null; } protected static > T closeFuture( T future ) { if( future != null ) future.cancel( true ); return null; } private static final ReferenceQueue QUEUE = new ReferenceQueue<>(); private static class CloseReference extends WeakReference { final Resource resource; CloseReference( Resource resource, T referent ) { super( referent, QUEUE ); this.resource = resource; } } public static void cleanup() { Reference reference; while( (reference = QUEUE.poll()) != null ) ((CloseReference) reference).resource.close(); } }