SageTV Community

SageTV Community (http://forums.sagetv.com/forums/index.php)
-   SageTV Beta Test Software (http://forums.sagetv.com/forums/forumdisplay.php?f=17)
-   -   SageTV V7 - API: FindWidgetBySymbol on remote UI context (http://forums.sagetv.com/forums/showthread.php?t=49550)

shadeblue.com 07-06-2010 10:41 PM

SageTV V7 - API: FindWidgetBySymbol on remote UI context
 
Hello, I am working on the InfoPopup/Caller ID plugin for SageTV V7 and have run into an issue that I need a little help with.

The release notes for Version 7.0.10 included this little GEM:

1. Added support for using SageTVClient context names to execute API calls on a SageTVClient from the SageTV server. The sage.SageTV.apiUI() call is used to do this; and the context names can be retrieved using the API call GetConnectedClients().


Using this new feature, my goal is to be able to send the popup instructions to SageTV clients and the local instance of SageTV UI running on a server where SageTV is running as a service.

I was able to successfully get a UI Context for the remote connected client using the GetConnectedClients() call. On my system it returns this value "/127.0.0.1:64556".

Next, I need to find a widget by ID and then execute the widget chain on this remote UI context. Here is a snippet of the current code. (This logic is currently working for HD Extenders, just not the remote UI context)

Code:

// find shadeBlue-InfoPopup dialog widget in SageTV           
String ui = "/127.0.0.1:64556";
Object widget1 = sage.SageTV.apiUI(ui, "FindWidgetBySymbol", new Object[] {"SBINFOPOPUP-START"});

if(widget1 == null)
{
    // debug
    logger.warn("WIDGET '"+configuration.getWidgetID()+"' NOT FOUND IN UI CONTEXT : "+ui);
    logger.warn("Unable to deliver YAC message to UI context: "+ui);
}
else
{
    // invoke shadeBlue-InfoPopup dialog widgets in SageTV
    sage.SageTV.apiUI(ui, "ExecuteWidgetChain", new Object[] {widget1});
}

(Technically speaking the ui context is not hard coded as shown here, but rather obtained dynamically at runtime using the "GetConnectedClients()" call. I illustrated it here as fixed, because I did not want to over complicate the example.)

The following failure info text is returned in the log file:

Code:

INFO - YAC caller ID message received: Caller=YAC Test Call / Number=(425) 555-1212 / Image=telephone.png
INFO - creating SageTV API and Global objects...
INFO - updating InfoPopup global context variables...
INFO - querying SageTV for list of UI contexts...
INFO - Processing message for SageTV UI context: /127.0.0.1:65220
INFO - Sending message 'Incoming Caller:
 
YAC Test Call
(425) 555-1212
 
' to SageTV UI context: /127.0.0.1:65220
WARN - WIDGET 'SBINFOPOPUP-START' NOT FOUND IN UI CONTEXT : /127.0.0.1:65220
WARN - Unable to deliver YAC message to UI context: /127.0.0.1:65220

So the "FindWidgetBySymbol" does not seem to be working when attempting to call this on a remote connected UI Context? I did open the STV on the running local client instance and it does contain the Widget ID. In fact, if I shut down the SageTV service and disable the service and run SageTV standalone (not as a service) then this code works fine.

Please help .. I'm stuck :-)
Thanks - SB

GKusnick 07-07-2010 01:28 AM

My guess is that not all object types are serialized correctly across remote API calls. Things like MediaFiles and Airings are, since the client needs to access those anyway. But there's no precedent for accessing remote widgets, so that's probably what's biting you. The call is executing correctly on the remote client (I'm guessing), but the returned widget is not making it back across the wire intact. Not sure if that counts as a bug or a known design limitation. There may just be too many interconnections between Widget objects to make serialization practical.

tmiranda 07-07-2010 04:44 AM

Odd timing. I actually tried serializing an Airing last night and from what I can tell they are not serializable at all. (Of course I'm a java noob so I may have been doing something wrong.)

stuckless 07-07-2010 06:05 AM

It's been my experience that not many, if any, of the native sage objects are java serializable. That's part of the reason why I ended up writing my sagex-apis, that support access to sage remote objects without needing them to be java serializable. (although is used primarily for testing purposes)

What is interesting about your situation is that your code works when running the sagetv client stand-alone, but not when it's running as a service. I don't know enough about SageTV and Windows to be helpful, but that would seem to me that this is not really a serialization issue, since why would the serialization fail simply because of how you ran the executable?

shadeblue.com 07-07-2010 08:05 AM

Quote:

Originally Posted by stuckless (Post 435093)
It's been my experience that not many, if any, of the native sage objects are java serializable. That's part of the reason why I ended up writing my sagex-apis, that support access to sage remote objects without needing them to be java serializable. (although is used primarily for testing purposes)

What is interesting about your situation is that your code works when running the sagetv client stand-alone, but not when it's running as a service. I don't know enough about SageTV and Windows to be helpful, but that would seem to me that this is not really a serialization issue, since why would the serialization fail simply because of how you ran the executable?

There is one main difference between when I run it standalone versus running it as as local client connecting to a SageTV service that I was not very clear on. In the standalone mode, the UI context is obtained via the call to SageApi.Api("GetUIContextNames") whereas when running as local instance connecting to SageTV service, the UI context is obtained via SageApi.Api("GetConnectedClients").

The UI context is also a different value either "SAGETV_PROCESS_LOCAL_UI" when running standalone or something like "/127.0.0.1:64556" when running as a service.


Quote:

protected String[] GetUIContextNames() {
// support backward compatibility for Sage 2.2
String[] UiContexts = new String[] {};
String[] localUiContexts = new String[] {};
String[] remoteUiContexts = new String[] {};
try
{
// 4.1
localUiContexts = (String[]) SageApi.Api("GetUIContextNames");
remoteUiContexts = (String[]) SageApi.Api("GetConnectedClients");

// combine arrays
UiContexts = new String[localUiContexts.length + remoteUiContexts.length];
System.arraycopy(localUiContexts, 0, UiContexts, 0, localUiContexts.length);
System.arraycopy(remoteUiContexts, 0, UiContexts, localUiContexts.length, remoteUiContexts.length);

} catch (InvocationTargetException e) {
// 4.1 API failed, try 2.2 API
try {
Object[] widgets = (Object[]) SageApi.Api("GetAllWidgets");
if (SageApi.Size(widgets) > 0) {
UiContexts = new String[] { LOCAL_UI_CONTEXT };
}
} catch (InvocationTargetException e2) {
// 2.2 API failed - no UI contexts
}
}
return UiContexts;
}

shadeblue.com 07-07-2010 08:09 AM

If only there were a "ExecuteWidgetChainBySymbol" API method that would accept the widget ID as a parameter, then I would not need to perform the find call and marshall objects back and forth .....

GKusnick 07-07-2010 10:30 AM

Quote:

Originally Posted by tmiranda (Post 435088)
I actually tried serializing an Airing last night and from what I can tell they are not serializable at all.

Quote:

Originally Posted by stuckless (Post 435093)
It's been my experience that not many, if any, of the native sage objects are java serializable.

I'm not talking about Java serialization; I'm talking about whatever serialization the Sage core does internally to make Wiz.bin accessible from SageTV Client. Clearly it's doing something since you can call methods in the MediaFileAPI, AiringAPI, FavoriteAPI, etc from SageTV Client and get sensible answers. However I surmise that WidgetAPI does not work since up to now there's been no requirement for remote WidgetAPI calls, so no support exists in the core to serialize Widget objects properly.

Narflex 07-07-2010 12:01 PM

Greg hit this one on the head. :) The protocol used for passing objects between the client & the server does NOT use Java based serialization. It uses its own protocol that supports a limited number of object types. This was never an issue previously; because any method that was remoted to a server automatically only used objects of a supported type. But now that you can call arbitrary methods on a client...not all of those methods will be able to pass values correctly.

We do not plan on extending the protocol so that all methods work remotely since many use Collections and other items that can store arbitrary Java objects; some of which may not be java.io.Serializable and they may also use SageTV DB objects which need to be passed by ID and are not compatible with java.io.Serializable. However, we can add support for more object types as needed in order to assist developers with specific problems.

For this issue; we just made an update so that any of the Widget API methods that take a 'Widget' as a parameter will also accept a symbol. And in that case, the symbol will be looked up and converted to a Widget. We also added support for converting a Widget to a symbol automatically when it's sent over the protocol. This means the client will send the Widget symbol back to the server for the OP's API call of "FindWidgetBySymbol". You'd then be able to use that same result in a remote call to "ExecuteWidgetChain" since the client would then automatically convert that symbol string back into a Widget. The server would never actually get a Widget object in this case.

This update should actually allow full usage of the Widget API in a remote context (at least I *think* so).

There was another bug that came up; which is that in the current implementation of servers executing API calls on clients, the local UI context was never set which prevented the Widget API calls from returning any value at all (that's why you got null instead of the default toString() representation of a Widget). This was also fixed for 7.0.12. So in actuality; there were two bugs here. :)

shadeblue.com 07-07-2010 12:18 PM

Hi Jeff,

Thank you so much for addressing this issue. And let me send a big THANK YOU on behalf of all users of the InfoPopup / Caller ID plugin. With support for these remote client calls it will greatly simplify the implementation of the caller id listener. Prior to this an instance of the listener plugin had to be installed and running at each client and for the local SageTV client instance running on the SageTV server, you would have to setup the listener plugin in the SageClient.properties file with a different port, and thus the YAC sender had to send to each listener on each port. While all this makes sense, it was a bit intimidating for some non-networking savvy users :-)

Love the new plugin architecture, plugin manager, and the remote UI context calls!

Thanks, SB

GKusnick 07-07-2010 03:04 PM

Quote:

Originally Posted by Narflex (Post 435172)
For this issue; we just made an update so that any of the Widget API methods that take a 'Widget' as a parameter will also accept a symbol. And in that case, the symbol will be looked up and converted to a Widget. We also added support for converting a Widget to a symbol automatically when it's sent over the protocol.

I read that and I thought, great solution, but yikes! How the heck am I going to wrap that? But you know what, I think it will just work transparently, since my wrappers don't actually care about the underlying type of the object being wrapped; they just unwrap it and pass it back in as needed.

shadeblue.com 07-17-2010 12:45 AM

Just upgraded to 7.0.12 and tested this. It all seems to be working great! The InfoPopup / Caller ID plugin has been updated to support this feature.

This is so much nicer where the running plugin can send out instructions to all the connected extenders and clients. No more need to run multiple YAC listeners on custom ports for SageTV clients!

Thanks Again,
SB


All times are GMT -6. The time now is 04:39 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Copyright 2003-2005 SageTV, LLC. All rights reserved.