Plugins Guide - nicho92/MtgDesktopCompanion GitHub Wiki
This guide explains the full plugin architecture in MTGCompanion and how to choose the right interface/abstract class based on your use case.
The core contract is MTGPlugin.
Each plugin family (provider, pricer, dao, notifier, server, etc.) extends MTGPlugin through a dedicated business interface (MTGCardsProvider, MTGDao, MTGPricesProvider, ...).
In practice, a concrete plugin class:
- Implements a business interface (usually through an abstract base class),
- Is instantiated by
PluginRegistry, - Is enabled/disabled from XML config,
- Reads/writes its own plugin-specific
.conffile.
MTGPlugin defines common behavior:
- lifecycle (
load,save,unload,isLoaded), - enablement (
enable,isEnable), - metadata (
getName,getVersion,getType,getStatut), - config (
getDefaultAttributes,setProperty,getString,getConfFile), - observer support (
addObserver,removeObserver,listObservers), - docs/auth (
getDocumentation,listAuthenticationAttributes,needAuthenticator).
It also defines structural enums:
-
PLUGINS: category (PROVIDER, DAO, PRICER, SERVER, etc.), -
STATUT: maturity (DEV/BETA/STABLE/DEPRECATED/BUGGED).
Design implication: every plugin must expose a stable identity (getName) and category (getType) to be properly registered and loaded.
Most implementations should extend AbstractMTGPlugin (directly or indirectly) instead of implementing MTGPlugin from scratch.
It already provides:
- plugin
.confloading/saving, - default attribute initialization (
initDefault+getDefaultAttributes), - typed config helpers (
getInt,getBoolean,getDouble,getFile, ...), - icon resolution (
/icons/plugins/<name>.pngwith fallback), - default documentation URL convention,
- partner/auth helpers,
- observer notification support.
-
getString(k)auto-creates missing keys fromgetDefaultAttributes(). -
isEnable()can be forced totruewhenisPartner()returnstrue. - conf files are organized per plugin type (
<conf_dir>/<type>/<name>.conf).
PluginRegistry is the central registry.
It stores mapping metadata: interface ↔ package to scan ↔ plugin type ↔ XML xpath.
Examples (from init()):
-
MTGCardsProvider→org.magic.api.providers.impl→PLUGINS.PROVIDER→/providers/provider, -
MTGDao→org.magic.api.dao.impl→PLUGINS.DAO→/daos/dao, -
MTGPricesProvider→org.magic.api.pricers.impl→PLUGINS.PRICER→/pricers/pricer.
- Controller injects XML config into registry (
setConfig). -
listPlugins(interface)reads XML entries (class+enable). - Instances are created by reflection (
newInstance). - Enabled/disabled state is applied.
- Instances are cached in
PluginEntry.
updateConfigWithNewModule() scans configured packages with Reflections and adds missing plugin classes into XML (non-abstract classes implementing MTGPlugin).
MTGControler:
- initializes
PluginRegistrywith active config, - persists plugin enablement (
setProperty(plugin, true/false)), - can add missing plugin class entries (
addProperty), - calls
unload()for all plugins on shutdown, - initializes critical plugins on startup (
MTGCardsProvider+MTGDao).
Practical rule:
- Pick the business interface matching your use case,
- Extend the associated abstract base class whenever available.
- Card data source:
MTGCardsProvider+AbstractCardsProvider - Price source:
MTGPricesProvider+AbstractPricesProvider - Database backend:
MTGDao+AbstractMagicDAO(or SQL/key-value variants) - Notifications:
MTGNotifier+AbstractMTGNotifier - Deck import:
MTGDeckSniffer+AbstractDeckSniffer - Deck/collection export:
MTGCardsExport+AbstractCardExport - Card images:
MTGPictureProvider+AbstractPicturesProvider - Embedded service/server:
MTGServer+AbstractMTGServer(orAbstractWebServer/AbstractWarServer) - Market dashboard:
MTGDashBoard+AbstractDashBoard - Tokens:
MTGTokensProvider+AbstractTokensProvider - News:
MTGNewsProvider+AbstractMagicNewsProvider - External store sync:
MTGExternalShop+AbstractExternalShop - AI integration:
MTGIA+AbstractIA - Sealed products:
MTGSealedProvider+AbstractSealedProvider
ScryFallProvider is a representative plugin implementation:
- extends
AbstractCardsProvider, - implements card retrieval/search behavior (
searchByCriteria,getCardById, ...), - defines defaults with
getDefaultAttributes(), - initializes caches/background warmup in
init().
This same pattern applies to other plugin families: let the abstract base handle plumbing, keep concrete class focused on business logic.
Define the category first (provider/pricer/dao/notifier/server/etc.).
Use the package path expected by PluginRegistry, otherwise auto-discovery may not pick it up.
Always define:
-
getName()(stable unique name), -
getType()(often already provided by abstract base), -
getDefaultAttributes()(keys + default values + descriptions).
Implement mandatory methods from your selected interface.
Use init() for warmup (cache/index/network setup). Avoid heavy constructor logic.
If plugin needs credentials/API key:
- return attribute names in
listAuthenticationAttributes(), -
needAuthenticator()becomes true automatically when the list is not empty.
Override getDocumentation() only if custom behavior is needed; default behavior builds a wiki URL convention.
- check class appears in plugin config,
- enable the plugin,
- verify generated
.conffile, - test from the UI/API flows consuming the interface.
-
Stable plugin name: avoid changing
getName()after release (conf/id impact). -
Complete defaults: every accessed config key should exist in
getDefaultAttributes(). - Resilient network behavior: log errors and degrade gracefully.
-
Keep constructors light: prefer
init()for heavy setup. -
Explicit maturity: override
getStatut()when relevant. -
Provide icon: add
/icons/plugins/<lowercase-name>.png.
- Correct business interface selected.
- Appropriate abstract base class used.
- Package matches
PluginRegistrydiscovery rules. -
getName()is stable and meaningful. -
getDefaultAttributes()is complete. -
init()is robust and non-blocking. - Auth fields declared when needed.
- Icon + documentation available.
- Functional validation done (enable/config/business calls).
- Need to retrieve card data →
MTGCardsProvider/AbstractCardsProvider - Need to retrieve prices →
MTGPricesProvider/AbstractPricesProvider - Need to persist/read collection data →
MTGDao/AbstractMagicDAO - Need to send notifications →
MTGNotifier/AbstractMTGNotifier - Need to run embedded services →
MTGServer/AbstractMTGServer