Link Search Menu Expand Document

Plugin contexts

Plugin contexts are answer to the question “how plugins communicate?”. Plugin root classes are seen by emuStudio, but not by plugins. Instead, plugins can register custom objects (called “contexts”) in the ContextPool object during plugin instantiation (in the constructor). ContextPool is a shared container of all plugin contexts. Plugins can also obtain contexts of other plugins, during plugin initialization. Then, plugin communicate by calling regular Java methods on the plugin context objects, obtained from context pool.

ContextPool is not thread-safe, so all operations on it should be performed in the same thread which called method Plugin.initialize().

Each plugin context must implement a Context interface (or it’s derivative). Interfaces which extend Context must be then annotated with PluginContext annotation. There are prepared some standard context interfaces in the API (CompilerContext, MemoryContext, CpuContext and DeviceContext), and those can be used when implementing plugin context class - or they can be further extended to provide customized versions of contexts.

Plugin context objects are registered in ContextPool as key-value pair, where the key is an context interface which the context implements, and value is the context object. A plugin can register none, one or many contexts. Single context object can be registered multiple times, if the keys (context interfaces) are different.

Sample custom context might be created like this:

@PluginContext
public interface SampleContext extends CpuContext {

   // custom methods...
}

And the context class might look as follows:

public class SampleContextImpl implements SampleContext {

   // implementation ...
}

Registration of this context might look as follows:

@PluginRoot(type = PLUGIN_TYPE.CPU, title = "Sample CPU emulator")
public class SamplePlugin implements CPU {

    public SamplePlugin(long pluginID, ApplicationApi emustudio, PluginSettings settings) {
        ContextPool contextPool = emustudio.getContextPool();

        SampleContext context = new SampleContextImpl();

        // We will register the same context two times, but by different context interfaces
        contextPool.register(pluginID, context, CpuContext.class); 
        contextPool.register(pluginID, context, SampleContext.class);
    }
}

If another plugin wants to obtain the context, it should do it in the Plugin.initialize() method:

@PluginRoot(type = PLUGIN_TYPE.DEVICE, title = "Sample device")
public class SampleDevice implements Device {

    ...

    @Override
    public void initialize() throws PluginInitializationException {

        // If obtaining the context is not vital, catch the exception
        SampleContext cpuContext = contextPool.getCPUContext(pluginID, SampleContext.class);

        ...
    }

    ...
}

If the requested context could not be found, or the plugins were not connected, an exception is thrown. If the plugin needs to obtain the context, the plugin should let the exception propagate to the caller, otherwise it should be catched.