CC-Tweaked/src/main/java/dan200/computercraft/core/apis/http/Resource.java

148 lines
3.8 KiB
Java

/*
* 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<T extends Resource<T>> implements Closeable
{
private final AtomicBoolean closed = new AtomicBoolean( false );
private final ResourceGroup<T> limiter;
protected Resource( ResourceGroup<T> 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 <R> WeakReference<R> createOwnerReference( R object )
{
return new CloseReference<>( this, object );
}
@Override
public final void close()
{
tryClose();
}
public boolean queue( Consumer<T> task )
{
@SuppressWarnings( "unchecked" )
T thisT = (T) this;
return limiter.queue( thisT, () -> task.accept( thisT ) );
}
protected static <T extends Closeable> 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 extends Future<?>> T closeFuture( T future )
{
if( future != null ) future.cancel( true );
return null;
}
private static final ReferenceQueue<Object> QUEUE = new ReferenceQueue<>();
private static class CloseReference<T> extends WeakReference<T>
{
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();
}
}