com.github.bjoernpetersen.jmusicbot.SongLoaderExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of musicbot Show documentation
Show all versions of musicbot Show documentation
Core library of MusicBot, which plays music from various providers.
package com.github.bjoernpetersen.jmusicbot;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
class SongLoaderExecutor implements Loggable {
private static volatile SongLoaderExecutor instance;
@Nonnull
private final ExecutorService service;
@Nonnull
private final Logger logger;
@Nonnull
private final Lock futureLock;
@Nonnull
private final Cache> futures;
private SongLoaderExecutor() {
this.service = Executors.newFixedThreadPool(2, new ThreadFactoryBuilder()
.setDaemon(true)
.setNameFormat("SongLoaderPool-%d")
.build()
);
this.logger = createLogger();
this.futureLock = new ReentrantLock();
futures = CacheBuilder.newBuilder()
.initialCapacity(8)
.maximumSize(128)
.weakKeys()
.removalListener((RemovalListener>) removalNotification -> {
Future future = removalNotification.getValue();
if (!future.isDone()) {
logWarning("Cancelling future because of cache removal");
future.cancel(true);
}
})
.build();
}
@Override
@Nonnull
public Logger getLogger() {
return logger;
}
/**
* Whether the specified song has been successfully loaded.
*
* This method will block until the loading is done.
*
* @param song a Song
* @return whether loading was successful
* @throws InterruptedException if the thread is interrupted while waiting for loading
* @throws IllegalStateException if the song is not scheduled for loading
*/
public final boolean hasLoaded(@Nonnull Song song) throws InterruptedException {
Future future = futures.getIfPresent(song);
if (future != null) {
try {
return !future.isCancelled() && future.get();
} catch (ExecutionException e) {
// ignore.
}
} else {
throw new IllegalStateException("song is not loading");
}
return false;
}
/**
* Asynchronously executed the SongLoader for the specified Song.
*
* @param song a Song
*/
public final void execute(@Nonnull Song song) {
if (futures.getIfPresent(song) == null) {
futureLock.lock();
try {
if (futures.getIfPresent(song) == null) {
logFiner("Enqueuing song load: " + song);
futures.put(song, service.submit(() -> song.getLoader().load(song)));
}
} finally {
futureLock.unlock();
}
}
}
public void close() {
service.shutdownNow();
SongLoaderExecutor.instance = null;
}
static SongLoaderExecutor getInstance() {
if (instance == null) {
synchronized (SongLoaderExecutor.class) {
if (instance == null) {
instance = new SongLoaderExecutor();
}
}
}
return instance;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy