com.github.bjoernpetersen.jmusicbot.PluginWrapper.kt 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.github.bjoernpetersen.jmusicbot.config.Config
import com.github.bjoernpetersen.jmusicbot.platform.Platform
import com.github.bjoernpetersen.jmusicbot.platform.Support
import com.github.bjoernpetersen.jmusicbot.playback.PlaybackFactory
import com.github.bjoernpetersen.jmusicbot.playback.SongEntry
import com.github.bjoernpetersen.jmusicbot.provider.DependencyMap
import com.github.bjoernpetersen.jmusicbot.provider.NoSuchSongException
import com.github.bjoernpetersen.jmusicbot.provider.Provider
import com.github.bjoernpetersen.jmusicbot.provider.Suggester
import com.github.zafarkhaja.semver.Version
import java.io.IOException
import java.util.HashSet
import kotlin.collections.ArrayList
typealias StateListener = (Plugin.State, Plugin.State) -> Unit
/**
* Wrapper for a plugin which provides access to the plugin's state and delegates all calls to the
* wrapped instance.
*
* This interface should not be directly implemented.
* Implement an interface which extends this interface as well as the specific plugin type instead (e.g. [ProviderWrapper]).
*
* @param P the type of the wrapped plugin
*/
interface PluginWrapper : Plugin {
/**
* The current state of the wrapped plugin.
*/
val state: Plugin.State
/**
* Convenience method to check whether the current state is [Plugin.State.ACTIVE].
*
* @return whether the wrapped plugin is active
*/
val isActive: Boolean
get() = state == Plugin.State.ACTIVE
/**
* The wrapped plugin.
*/
val wrapped: P
/**
* The config entries the plugin returned for [initializeConfigEntries].
* The returned list will be empty if the state is not at least [Plugin.State.CONFIG].
*/
val configEntries: List
/**
* Add a state listener which will be called every time the plugin state changes.
*/
fun addStateListener(listener: StateListener)
/**
* Remove a state listener added in [addStateListener].
*/
fun removeStateListener(listener: StateListener)
}
/**
* Default implementation of [PluginWrapper]. The only extensions can be found in this module.
*/
sealed class DefaultPluginWrapper constructor(override val wrapped: T) : PluginWrapper {
private val listeners: MutableSet = HashSet()
override var configEntries: List = emptyList()
override var state: Plugin.State = Plugin.State.INACTIVE
protected set(value) {
val old = field
field = value
listeners.forEach { it(old, value) }
}
override fun initializeConfigEntries(config: Config): List {
if (state < Plugin.State.CONFIG) {
configEntries = wrapped.initializeConfigEntries(config)
state = Plugin.State.CONFIG
}
return configEntries
}
override fun getMissingConfigEntries(): List = wrapped.missingConfigEntries
override fun destructConfigEntries() {
if (state > Plugin.State.CONFIG) {
throw IllegalStateException()
} else if (state < Plugin.State.CONFIG) {
return
}
configEntries = emptyList()
wrapped.destructConfigEntries()
state = Plugin.State.INACTIVE
}
override fun addStateListener(listener: StateListener) {
listeners.add(listener)
}
override fun removeStateListener(listener: StateListener) {
listeners.remove(listener)
}
override fun getReadableName(): String = wrapped.readableName
override fun getSupport(platform: Platform): Support = wrapped.getSupport(platform)
override fun getMinSupportedVersion(): Version = wrapped.minSupportedVersion
override fun getMaxSupportedVersion(): Version = wrapped.maxSupportedVersion
@Throws(IOException::class)
override fun close() {
if (state < Plugin.State.ACTIVE) {
return
}
try {
wrapped.close()
} finally {
state = Plugin.State.CONFIG
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as DefaultPluginWrapper<*>
if (wrapped != other.wrapped) return false
return true
}
override fun hashCode(): Int = wrapped.hashCode()
}
/**
* A [PluginWrapper] for [PlaybackFactory] which also implements PlaybackFactory by delegation.
*/
interface PlaybackFactoryWrapper : PluginWrapper, PlaybackFactory
/**
* A default implementation of [PlaybackFactoryWrapper].
*/
open class DefaultPlaybackFactoryWrapper(plugin: PlaybackFactory) : DefaultPluginWrapper(plugin),
PlaybackFactoryWrapper {
@Throws(InitializationException::class, InterruptedException::class)
override fun initialize(initStateWriter: InitStateWriter) {
if (state < Plugin.State.CONFIG) {
throw IllegalStateException()
} else if (state == Plugin.State.ACTIVE) {
return
}
wrapped.initialize(initStateWriter)
state = Plugin.State.ACTIVE
}
override fun getBases(): Collection> = wrapped.bases
}
/**
* A [PluginWrapper] for [Provider] which also implements Provider by delegation.
*/
interface ProviderWrapper : PluginWrapper, Provider
/**
* A default implementation of [ProviderWrapper].
*/
open class DefaultProviderWrapper(plugin: Provider) : DefaultPluginWrapper(plugin), ProviderWrapper {
private val _suggesters: MutableList = ArrayList(16)
val suggesters: List
get() = _suggesters
fun addSuggester(suggester: Suggester) = _suggesters.add(suggester)
override fun getPlaybackDependencies(): Set> = wrapped.playbackDependencies
override fun getId(): String = wrapped.id
@Throws(InitializationException::class, InterruptedException::class)
override fun initialize(initStateWriter: InitStateWriter, manager: PlaybackFactoryManager) {
if (state < Plugin.State.CONFIG) {
throw IllegalStateException()
} else if (state == Plugin.State.ACTIVE) {
return
}
wrapped.initialize(initStateWriter, manager)
state = Plugin.State.ACTIVE
}
override fun search(query: String): List = wrapped.search(query)
@Throws(NoSuchSongException::class)
override fun lookup(id: String): Song = wrapped.lookup(id)
override fun getBaseClass(): Class = wrapped.baseClass
}
/**
* A [PluginWrapper] for [Suggester] which also implements Suggester by delegation.
*/
interface SuggesterWrapper : PluginWrapper, Suggester
/**
* A default implementation of [SuggesterWrapper].
*/
open class DefaultSuggesterWrapper(plugin: Suggester) : DefaultPluginWrapper(plugin), SuggesterWrapper {
override fun suggestNext(): Song = wrapped.suggestNext()
override fun getNextSuggestions(maxLength: Int): List = wrapped.getNextSuggestions(maxLength)
override fun getId(): String = wrapped.id
@Throws(InitializationException::class, InterruptedException::class)
override fun initialize(initStateWriter: InitStateWriter, dependencies: DependencyMap) {
if (state < Plugin.State.CONFIG) {
throw IllegalStateException()
} else if (state == Plugin.State.ACTIVE) {
return
}
wrapped.initialize(initStateWriter, dependencies)
state = Plugin.State.ACTIVE
}
override fun dislike(song: Song) {
wrapped.dislike(song)
}
override fun notifyPlayed(entry: SongEntry) {
wrapped.notifyPlayed(entry)
}
override fun removeSuggestion(song: Song) {
wrapped.removeSuggestion(song)
}
override fun getDependencies(): Set> = wrapped.dependencies
override fun getOptionalDependencies(): Set> = wrapped.optionalDependencies
}
/**
* A [PluginWrapper] for [AdminPlugin] which also implements [AdminPlugin] by delegation.
*/
interface AdminPluginWrapper : PluginWrapper, AdminPlugin
/**
* A default implementation of [AdminPluginWrapper].
*/
open class DefaultAdminPluginWrapper(plugin: AdminPlugin) : DefaultPluginWrapper(plugin),
AdminPluginWrapper {
@Throws(InitializationException::class, InterruptedException::class)
override fun initialize(writer: InitStateWriter, musicBot: MusicBot) {
if (state < Plugin.State.CONFIG) {
throw IllegalStateException()
} else if (state == Plugin.State.ACTIVE) {
return
}
wrapped.initialize(writer, musicBot)
state = Plugin.State.ACTIVE
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy