Registering a new Aspect from a Plugin failing (1 Viewer)

McGoober

Retired Team Member
  • Premium Supporter
  • August 13, 2006
    122
    105
    Cambridge, UK
    Home Country
    United Kingdom United Kingdom
    Sanity check here... I must be missing something.

    Ok, so I have a plugin which needs to register a new aspect so I can store extra data about media items. So I create the new aspect and go to register it. However when I do (I'm doing this from IPluginStateTracker.Activated()) I get an exception in the core.

    Code:
    System.NullReferenceException: Object reference not set to an instance of an object.
      at MediaPortal.Backend.Services.MediaLibrary.MediaLibrary.AddMediaItemAspectStorage(MediaItemAspectMetadata miam) in E:\users\jason leonard\work\mediaportal-2\MediaPortal\Source\Core\MediaPortal.Backend\Services\MediaLibrary\MediaLibrary.cs:line 956
      at MediaPortal.Backend.Services.MediaManagement.MediaItemAspectTypeRegistration.RegisterLocallyKnownMediaItemAspectType(MediaItemAspectMetadata miam) in E:\users\jason leonard\work\mediaportal-2\MediaPortal\Source\Core\MediaPortal.Backend\Services\MediaManagement\MediaItemAspectTypeRegistration.cs:line 51
      at MediaPortal.Extensions.MediaServer.MediaServerPlugin.Activated(PluginRuntime pluginRuntime)
      at MediaPortal.Common.Services.PluginManager.PluginManager.TryActivate(PluginRuntime plugin) in E:\users\jason leonard\work\mediaportal-2\MediaPortal\Source\Core\MediaPortal.Common\Services\PluginManager\PluginManager.cs:line 930

    Apparently the MediaLibrary service hasn't been started yet, and therefore fails to register the aspect.
    So the question is.. when do I get a call from the IPluginStateTracker that I can use to register the aspect?
     

    McGoober

    Retired Team Member
  • Premium Supporter
  • August 13, 2006
    122
    105
    Cambridge, UK
    Home Country
    United Kingdom United Kingdom
    Yeah, I was wondering if something like that was needed...
    Here is my metadata extractor element...
    Code:
    <Register Location="/Media/MetadataExtractors">
    Does anyone know the magic incarnation for the Location field I would need for this?
     

    McGoober

    Retired Team Member
  • Premium Supporter
  • August 13, 2006
    122
    105
    Cambridge, UK
    Home Country
    United Kingdom United Kingdom
    I've found another way of doing it, but doesn't seem like the right thing to do.
    I've registered for events from the IMessageBroker, and I watch for the state "Running". This solves the problem but creates a race condition between the UPNP device starting and my aspect/resourcemodule registering.
     

    MJGraf

    Retired Team Member
  • Premium Supporter
  • January 13, 2006
    2,478
    1,385
    Hi Leonard,
    well, that's a good point - just had a look into the code:

    At startup, the ApplicationLauncher calls

    PluginManager.Startup - this is where IPluginStateTracker.Activated is called for all plugins set to autoactivate --> NRE
    ApplicationCore.StartCoreServices
    BackupExtensions.StartupBackendServices - this is where the MediaLibrary is instantiated --> too late...
    ApplicationCore.RegisterDefaultMediaItemAspectTypes

    And behind the last line is a comment that says: to be done after backed services are running

    That looks like a conceptual bug to me, but in the end this is really a question for @morpheus_xx or @Albert. I don't know whether PluginManager.Startup should be called after the backend services are running? To me that would make sense because as a plugin author I would assume that the backend services are running when my plugin reaches the active state, but I don't know whether there's another dependency I'm not aware of...

    Good luck and keep up your great work!
    Michael
     

    MJGraf

    Retired Team Member
  • Premium Supporter
  • January 13, 2006
    2,478
    1,385
    oh well, that's not going to be easy...

    I should have known that anything in MP2 is a plugin - such as the database. So if you startup the PluginManager after you try to startup the BackendServices this gives you a "There is no database present in the system" exception. Not a good idea...

    My first thought was to implement something like a "SystemRunning"-method in IPluginStateTracker so that you don't have to listen to system messages just for registering MIAs. But then again I'm not sure if there's a problem with the ApplicationLauncher.

    After
    ApplicationCore.RegisterDefaultMediaItemAspectTypes(); // To be done after backend services are running

    it continues with:
    mediaAccessor.Initialize();
    systemStateService.SwitchSystemState(SystemState.Running, true);
    BackendExtension.ActivateImporterWorker(); // To be done after default media item aspect types are present and when the system is running (other plugins might also install media item aspect types)

    So I suppose that plugins should have a possibility to register MIAs before the ImportWorker is started. Since my understanding of messages in MP2 is that they are decoupled from the main thread, I'm also not sure if your implementation now, Leonard, is guaranteed to work. If your plugin takes more time to register the MIAs, they may get registered after the main thread activated the ImportWorker.

    Conclusion for me is that we would indeed need something like IPluginStateTracker.SystemRunning(), but we would have to make sure that it is called before ApplicationLauncher activates the ImportWorker. Since this is deep down in the core of MP2, I'll leave that to the Pros now ;)

    cheers,
    Michael
     
    Last edited:

    McGoober

    Retired Team Member
  • Premium Supporter
  • August 13, 2006
    122
    105
    Cambridge, UK
    Home Country
    United Kingdom United Kingdom
    See, now I'm a bit torn between having a callback to perform registration in or adding registration items into the plugin.xml...

    Do we do...
    Code:
    public class MediaServerPlugin : IPluginStateTracker
    {
        public void SystemRunning()
        {
          ServiceRegistration.Get<IMediaItemAspectTypeRegistration>()
            .RegisterLocallyKnownMediaItemAspectType(DlnaAspect.Metadata);
        }
    }

    or....
    Code:
    <Register Location="/Database/Aspects">
       <Instance
            Id="DlnaAspect"
            ClassName="MediaPortal.Extensions.MediaServer.Aspects.DlnaAspect"/>
    </Register>

    My concern is that all registrations for my plugin must happen before the UPNP subsystem is brought up. I haven't as yet drilled down to the call that happens in but according to the log it's after the database subsystem is active. If I was to register everything in the plugin.xml then it's up to the core team to decide when registration of the different parts actually occurs, and not me. This would mean that if a core init change were to happen I would (should) be decoupled from the changes.
    Make sense?
     

    MJGraf

    Retired Team Member
  • Premium Supporter
  • January 13, 2006
    2,478
    1,385
    Makes absolute sense!

    But to be honest, I still didn't understand the difference between registering something via plugin.xml an registering the same thing with a call within Plugin.Activated. Let's take registering a service:

    Morpheus registers his FanArtService in FanArtServicePlugin.Activated with a call to ServiceRegistration.Set<IFanArtService>(new FanArtService());
    There's nothing in plugin.xml regarding the service.

    On the other hand, the SeriesTVDbMatcher and the MovieTheMovieDbMatcher in the OnlineLibraries are registered only via plugin.xml.

    The reason for the first example may be that after registering the service, he adds the respective service implementation to the Backend UPNP device and wants to make sure that this happens after the service is registered with the service registration. On the other hand, the reason for the second example could be as easy as there is no PluginStateTracker for the OnlineLibraries - hence to Activated method.

    As to your question re startup order:

    ApplicationLauncher first activates the plugins and thereby starts all services provided by plugins.
    Then it starts ApplicationCore.StartCoreServices();
    Then we start BackendExtension.StartupBackendServices();
    And after that the DefaultMediaItemAspectTypes are registered.

    The UPNP subsytem is the UPNPBackendServer, which is contained in MediaPortal.Backend.Services.BackendServer. This is therefore started as "BackendService", which is according to the above before the Default MIAs are registered. I'm therefore not sure whether it would be necessary at all to register your aspect before the UPNPBackendServer ist running. The default MIAs are registered after that as well...

    And to be honest, I'm also not sure whether it is necessary to register your aspect before the ImportWorker starts. At least there should be as message informing all interested services that the registered MIAs have changed. But I'm quite sure that this doesn't work (yet), because there seems to be a bug with the message. Maybe @morpheus_xx can check this:

    In the ContentDirectoryMessaging class (which is called by MediaLibrary.AddMediaItemAspectStorage) I found:
    public static void SendPlaylistsChangedMessage()
    {
    SystemMessage msg = new SystemMessage(MessageType.PlaylistsChanged);
    ServiceRegistration.Get<IMessageBroker>().Send(CHANNEL, msg);
    }
    public static void SendMIATypesChangedMessage()
    {
    SystemMessage msg = new SystemMessage(MessageType.PlaylistsChanged);
    ServiceRegistration.Get<IMessageBroker>().Send(CHANNEL, msg);
    }

    In my understanding this is a copy and paste bug - in the second method this should be:
    SystemMessage msg = new SystemMessage(MessageType.MIATypesChanged);

    At least UPnPContentDirectoryServiceImpl checks for this message and it looks like it never received one... :D
    In the ImportWorker, however, I couldn't find anything listening to that message.

    This whole thing indeed brings me to the conclusion that it may be much easier for plugin programmers if they did not have to take care about all this when they register new MIAs - therefore at first glance I would prefer the plugin.xml solution. But this again requires the PluginRuntime to be extended for automatically registering MIAs - and I have no clue how to do that...

    Michael
     

    morpheus_xx

    Retired Team Member
  • Team MediaPortal
  • March 24, 2007
    12,073
    7,459
    Home Country
    Germany Germany
    In the ContentDirectoryMessaging class (which is called by MediaLibrary.AddMediaItemAspectStorage) I found:
    public static void SendPlaylistsChangedMessage()
    {
    SystemMessage msg = new SystemMessage(MessageType.PlaylistsChanged);
    ServiceRegistration.Get<IMessageBroker>().Send(CHANNEL, msg);
    }
    public static void SendMIATypesChangedMessage()
    {
    SystemMessage msg = new SystemMessage(MessageType.PlaylistsChanged);
    ServiceRegistration.Get<IMessageBroker>().Send(CHANNEL, msg);
    }

    In my understanding this is a copy and paste bug - in the second method this should be:
    SystemMessage msg = new SystemMessage(MessageType.MIATypesChanged);

    Good finding, fixed this in dev branch!

    The registration issue itself needs more work ;)
     

    Users who are viewing this thread

    Top Bottom