SageTV Community  

Go Back   SageTV Community > SageTV Development and Customizations > SageTV Studio
Forum Rules FAQs Community Downloads Today's Posts Search

Notices

SageTV Studio Discussion related to the SageTV Studio application produced by SageTV. Questions, issues, problems, suggestions, etc. relating to the Studio software application should be posted here.

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 02-24-2010, 02:15 PM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Extenders and how they access static variables

I am having some confusion on extenders and how exactly they access public static's from java. Do they each keep their own jvm copy or do all extenders share?

Let's say for instance I am building a hash

Code:
private static HashMap<String,String> valuehash = new HashMap<String,String>();

public static void SetHashValues(){
valuehash.put("1","1");
valuehash.put("2","2");
valuehash.put("2","2");
}

public static String getvalue(String key){
return valuehash.get(key);}
(
If I am setting the values of that hash different on each extender are they going to get crossed or each keep their own copy of the hash in memory?

cheers and thanks again,

pluckyhd
Reply With Quote
  #2  
Old 02-24-2010, 03:01 PM
stuckless's Avatar
stuckless stuckless is offline
SageTVaholic
 
Join Date: Oct 2007
Location: London, Ontario, Canada
Posts: 9,713
All extenders run in the same jvm and therefore a singleton (public static) variable will be shared by all extender connections.

To get around this, you can use the UIContext as a main key, and then keep each extenders data separated by their ui context. This has its own set of problems since in SageTV 6, calling GetUIContext from within java code returns null. the sagex.apis get around this by testing the thread name (recommendation by jeff).

As a rule of thumb in a multi-user environment... you don't want to make anything public static unless you intend for it to be shared by ALL users.
Reply With Quote
  #3  
Old 02-24-2010, 03:09 PM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Quote:
Originally Posted by stuckless View Post
All extenders run in the same jvm and therefore a singleton (public static) variable will be shared by all extender connections.

To get around this, you can use the UIContext as a main key, and then keep each extenders data separated by their ui context. This has its own set of problems since in SageTV 6, calling GetUIContext from within java code returns null. the sagex.apis get around this by testing the thread name (recommendation by jeff).

As a rule of thumb in a multi-user environment... you don't want to make anything public static unless you intend for it to be shared by ALL users.
what are the other options besides making it a public static?
Reply With Quote
  #4  
Old 02-24-2010, 03:18 PM
stuckless's Avatar
stuckless stuckless is offline
SageTVaholic
 
Join Date: Oct 2007
Location: London, Ontario, Canada
Posts: 9,713
You can have a public static to keep track of extenders....
Code:
public static final Map<String, ExtenderData> extenders = new HashMap<String,ExtenderData>();
Later when you need to set some data for the extender, you can get the ExtenderData using the uicontext.
Code:
ExtenderData data = extenders.get(uicontext);
if (data!=null) return data.getSomeStoredValue();
In this case, I'm assuming that ExtenderData is one of your objects, but it could just as easily by another Map.
Reply With Quote
  #5  
Old 02-24-2010, 03:24 PM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Quote:
Originally Posted by stuckless View Post
You can have a public static to keep track of extenders....
Code:
public static final Map<String, ExtenderData> extenders = new HashMap<String,ExtenderData>();
Later when you need to set some data for the extender, you can get the ExtenderData using the uicontext.
Code:
ExtenderData data = extenders.get(uicontext);
if (data!=null) return data.getSomeStoredValue();
In this case, I'm assuming that ExtenderData is one of your objects, but it could just as easily by another Map.
That is a interesting way to do it and seems logical enough.

guessing I have to redo all my property file storing and everything....ahh never ending when you are still learning.
Reply With Quote
  #6  
Old 02-24-2010, 03:36 PM
stuckless's Avatar
stuckless stuckless is offline
SageTVaholic
 
Join Date: Oct 2007
Location: London, Ontario, Canada
Posts: 9,713
Quote:
Originally Posted by PLUCKYHD View Post
That is a interesting way to do it and seems logical enough.

guessing I have to redo all my property file storing and everything....ahh never ending when you are still learning.
Yeah.. I ran into this quite early on with the Phoenix stuff. I basically did something similar there as well.
Reply With Quote
  #7  
Old 02-24-2010, 03:36 PM
jphipps jphipps is offline
Sage Expert
 
Join Date: Aug 2006
Location: Maryland
Posts: 512
I had originally used a syncronizedMap to store local data for each context, which was nice because I could examine the map and see all the clients that were connected. I switched over to InheritableThreadLocal() variables, which seems to be working well, but I loose the ability to examine the other extenders data...

Thanks,
Jeff
Reply With Quote
  #8  
Old 02-24-2010, 03:45 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
If this is code that's going to be called from an STV, then another fairly straightforward option is to not use statics at all, but instead create a class instance in the ApplicatedStarted hook (which now fires when your STV is loaded) and pass that in to your method calls. That's how object-oriented code is supposed to work: you make an instance of the class and use it for all your method calls.
__________________
-- Greg
Reply With Quote
  #9  
Old 02-24-2010, 03:47 PM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Quote:
Originally Posted by jphipps View Post
I had originally used a syncronizedMap to store local data for each context, which was nice because I could examine the map and see all the clients that were connected. I switched over to InheritableThreadLocal() variables, which seems to be working well, but I loose the ability to examine the other extenders data...

Thanks,
Jeff
Yeah I have been trying the InheritableThreadLocal() but it doesn't like me

Code:
private static InheritableThreadLocal testmap = new InhertibableThreadLocal();

private static HashMap<String,String> valuehash = new HashMap<String,String>();

public static void SetHashValues(){
valuehash.put("1","1");
valuehash.put("2","2");
valuehash.put("3","3");
testmap.set(valuehash);
logger(testmap.get());
}

public static String getvalue(String key){
logger(testmap.get());
return ((HashMap<String,String>)valuehash.get()).get(key);}
The first logger will print out the contents current (1=1,2=2,3=3)
but when I call Getvalue that logger returns null for the testmap....

Any ideas?
Reply With Quote
  #10  
Old 02-24-2010, 03:49 PM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Quote:
Originally Posted by GKusnick View Post
If this is code that's going to be called from an STV, then another fairly straightforward option is to not use statics at all, but instead create a class instance in the ApplicatedStarted hook (which now fires when your STV is loaded) and pass that in to your method calls. That's how object-oriented code is supposed to work: you make an instance of the class and use it for all your method calls.
You are making my google work awful hard for me....Could you give me a pointer to what you are referring to can't seem to grasp it...
Reply With Quote
  #11  
Old 02-24-2010, 07:03 PM
jphipps jphipps is offline
Sage Expert
 
Join Date: Aug 2006
Location: Maryland
Posts: 512
Greg's suggestion is to instantiate an instance of a class in the STV and you pass the variable as the first parm to the method and it will call the method within that instance of the class, such as:

varx = new_ortus_class();
ortus_class_method(varx,otherparms);

I tested a sample of what you posted, and it worked as it should...

Thanks,
Jeff
Reply With Quote
  #12  
Old 02-24-2010, 07:24 PM
stuckless's Avatar
stuckless stuckless is offline
SageTVaholic
 
Join Date: Oct 2007
Location: London, Ontario, Canada
Posts: 9,713
Quote:
Originally Posted by PLUCKYHD View Post
Code:
private static InheritableThreadLocal testmap = new InhertibableThreadLocal();

// this will be shared by all threads
private static HashMap<String,String> valuehash = new HashMap<String,String>();

public static void SetHashValues(){
// you are changing the values of the map for all threads
valuehash.put("1","1");
valuehash.put("2","2");
valuehash.put("3","3");
// this sets this threads value to be a reference to the already public static map, doesn't do what you need/want
testmap.set(valuehash);
logger(testmap.get());
}

public static String getvalue(String key){
// can be null, if the this thread hasn't called SetHashValues()
logger(testmap.get());
// this return the shared instance of valuehash
return ((HashMap<String,String>)valuehash.get()).get(key);}
The first logger will print out the contents current (1=1,2=2,3=3)
but when I call Getvalue that logger returns null for the testmap....

Any ideas?
Plucky, I'm not sure I quite understand that code... was that a direct cut and paste? You have a singleton thread local, which is fine, but then you have a singleton valuehash, which defeats the purpose of the threadlocal, since that singleton instance is still going to be shared by all threads.

ThreadLocals work like like... Create one, initialize it, and then for the lifetime of that thread, you can access that variable and it will contain a value that is specific to that varialbe (unless you share it, as you've done). For each new thread created, the threadlocal has to initialized, if it's not, then the value in the threadlocal will be null, even if it has been initialized by another thread. ie, the purpose of the threadlocal is to allow different threads to access the same "variable" but have different states. In java it's typically used in web applications.
Reply With Quote
  #13  
Old 02-25-2010, 05:47 AM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Quote:
Originally Posted by stuckless View Post
Plucky, I'm not sure I quite understand that code... was that a direct cut and paste? You have a singleton thread local, which is fine, but then you have a singleton valuehash, which defeats the purpose of the threadlocal, since that singleton instance is still going to be shared by all threads.

ThreadLocals work like like... Create one, initialize it, and then for the lifetime of that thread, you can access that variable and it will contain a value that is specific to that varialbe (unless you share it, as you've done). For each new thread created, the threadlocal has to initialized, if it's not, then the value in the threadlocal will be null, even if it has been initialized by another thread. ie, the purpose of the threadlocal is to allow different threads to access the same "variable" but have different states. In java it's typically used in web applications.
stuckless,

I created the shared hash so I could build the has I wanted to pass to the threadlocal hash. I should move that into the actually servalue call vs defining above the class I can see how that would clash. But in
And no that wasn't a copy and paste and a poor code example on my part . I cast the threadlocalvarible back to a hash and get a key from it not the other hash. My problem is the two debugging calls is what I do have in my code on after setting the value of the threadlocal hash(and debug log shows values are there) then the other trying to log the values in another call afternthey have been set and it returns null or some reason., jeff(ortus jeff) emailed me and said the same code worked for him so I don't know....

I will give it a go plan on reading up on the differences between public static and just public as I don't think I understand those as I thought I did. I did find out if it is just public and not static i can't call it within studio now just want to learn the reason why.

Cheers and appreciate once again helping me better myself in this experience.
Reply With Quote
  #14  
Old 02-25-2010, 06:44 AM
stuckless's Avatar
stuckless stuckless is offline
SageTVaholic
 
Join Date: Oct 2007
Location: London, Ontario, Canada
Posts: 9,713
Quote:
Originally Posted by PLUCKYHD View Post
stuckless,

I created the shared hash so I could build the has I wanted to pass to the threadlocal hash. I should move that into the actually servalue call vs defining above the class I can see how that would clash. But in
And no that wasn't a copy and paste and a poor code example on my part . I cast the threadlocalvarible back to a hash and get a key from it not the other hash. My problem is the two debugging calls is what I do have in my code on after setting the value of the threadlocal hash(and debug log shows values are there) then the other trying to log the values in another call afternthey have been set and it returns null or some reason., jeff(ortus jeff) emailed me and said the same code worked for him so I don't know....

I will give it a go plan on reading up on the differences between public static and just public as I don't think I understand those as I thought I did. I did find out if it is just public and not static i can't call it within studio now just want to learn the reason why.

Cheers and appreciate once again helping me better myself in this experience.
Plucky... in a nutshell.. a public static variable means that their is only one instance per classloader, so for sagetv, you can think of a public static as simply a "global" and shared with everyone (if it's public static).

I think that threadlocal is probably overcomplicating things for you... this is the general flow...
Code:
public static final InheritableThreadLocal data = new IneritableThreadLocal();

public class DataManager() {
   public static Object getData() {
       Map extenderData = data.get();
       if (extenderData==null) {
           // no data for this thread, so initialize it.
           extenderData = createInitialData();
           data.put(extenderData);
       }
       return extenderData;
   }
}
While the code above ensures that each thread has it's own copy of the data, it's not clear that the intention here is that each extender has it's own copy of data. The assumption is that each extender on the server runs in it's own thread and as a result has their own data (for that thread).

Personally I think it's clearer to either use a public static data store that is keyed of the UIContext, since it clearly indicates that you want some for that extender's ui context.

Or, since you are working in the STV, using Greg's approach, where you create the object on application started hook, is probably the best, especially if there is an application terminated event that can be used to clean up the data, if needed.
Reply With Quote
  #15  
Old 02-25-2010, 06:51 AM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Quote:
Originally Posted by stuckless View Post
Plucky... in a nutshell.. a public static variable means that their is only one instance per classloader, so for sagetv, you can think of a public static as simply a "global" and shared with everyone (if it's public static).
This is true except for client pc's correct? As client pc's run their own instance of java so they would have their static as their own right?

Quote:
Originally Posted by stuckless View Post

Personally I think it's clearer to either use a public static data store that is keyed of the UIContext, since it clearly indicates that you want some for that extender's ui context.

Or, since you are working in the STV, using Greg's approach, where you create the object on application started hook, is probably the best, especially if there is an application terminated event that can be used to clean up the data, if needed.
I can probably get by with your approach easier than Greg's since I don't fully understand his approach but I do understand your approach. Come to think of it I think I like your approach as the hashmap will stay in place even after an extender is shut down as long as the service is running correct? That means I wouldn't have to rebuild them when the extenders starts up if they are already in place (of course some like property files would need to be).

Thanks again
Reply With Quote
  #16  
Old 02-25-2010, 08:53 AM
stuckless's Avatar
stuckless stuckless is offline
SageTVaholic
 
Join Date: Oct 2007
Location: London, Ontario, Canada
Posts: 9,713
Quote:
Originally Posted by PLUCKYHD View Post
This is true except for client pc's correct? As client pc's run their own instance of java so they would have their static as their own right?
Yeah, I should have clarified... shared by "everyone" just means shared by all extenders that are running in the server jvm. The client jvms don't need to worry about this.

Quote:
I can probably get by with your approach easier than Greg's since I don't fully understand his approach but I do understand your approach. Come to think of it I think I like your approach as the hashmap will stay in place even after an extender is shut down as long as the service is running correct? That means I wouldn't have to rebuild them when the extenders starts up if they are already in place (of course some like property files would need to be).
Something to consider as well is having a TimerTask that runs maybe once per day to clean out any Extenders that are not currently being used, especially if there is going to be lots of data in there.
Reply With Quote
  #17  
Old 02-25-2010, 09:07 AM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Quote:
Originally Posted by stuckless View Post
Something to consider as well is having a TimerTask that runs maybe once per day to clean out any Extenders that are not currently being used, especially if there is going to be lots of data in there.
Yeah was thinking about that probably run it will my startup runnable class on rescans to go ahead and check each key. It really isn't to much data mostly property files and some ui variables so shouldn't get to big but better safe than sorry
Reply With Quote
  #18  
Old 02-25-2010, 10:30 AM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Just wanted to say I have all my statics that I had shared (that I didn't want extenders to share) in their own hash's now using the uicontext as the key and all seems to still be working. Wanted to thanks for the advice.

Reply With Quote
  #19  
Old 02-25-2010, 12:32 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
Quote:
Originally Posted by PLUCKYHD View Post
I can probably get by with your approach easier than Greg's since I don't fully understand his approach but I do understand your approach.
There's nothing very complicated about what I suggested. Just instantiate the class using new, and then pass the instance in to your class methods. This is just the normal process for working with Java objects from Studio, as illustrated on p. 151 of the Studio manual or in jphipps' post above.

So:

Code:
Hook ApplicationStarted
  If myData == null
    AddGlobalContext("myData", new_myPackage_myClass())

elsewhere
  myPackage_myClass_method(myData, args)

Hook ApplicationExiting
  myPackage_myClass_CleanUp(myData)
  myData = null
Again, just pass in the myData instance whenever you call one of your methods. All the instance data for a particular client can then live directly inside that class, not static, with no need for hash tables, UI contexts, or thread local storage to access it. Just declare it directly in the class, like you normally would when writing a simple Java app. All perfectly vanilla, nothing tricky about it.

Of course it's your code and you can do it however you like. But to be honest it boggles me a bit when people find all that complicated stuff with hash tables and such easier to deal with than just using Java objects the way they're meant to be used.
__________________
-- Greg
Reply With Quote
  #20  
Old 02-25-2010, 12:39 PM
PLUCKYHD PLUCKYHD is offline
SageTVaholic
 
Join Date: Dec 2007
Posts: 6,257
Quote:
Originally Posted by GKusnick View Post

Of course it's your code and you can do it however you like. But to be honest it boggles me a bit when people find all that complicated stuff with hash tables and such easier to deal with than just using Java objects the way they're meant to be used.
For me hashtables I know and that is why it is easier for me Your way kind of makes since and I will try and grasp it (maybe I am just dense at the moment). Been pretty much teaching myself as you know with help from you guys so there is allot I don't understand and it is probably just the simply fact I understand Sean's method and not yours. After reading your example I do think I understand it now and wasn't aware I can just create a instance like that.

I am guessing I would need to create a instance for every class that this is needed is that correct?

cheers and thanks for the helpful example
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
scriptable internet access while maintaining LAN access korben_dallas The SageTV Community 5 12-21-2009 06:11 AM
Limiting Tuner Access for Specific HD-200 Extenders Greg SageTV Media Extender 16 12-05-2009 09:04 AM
Passing variables to a method fafurd SageTV Studio 2 12-04-2006 12:23 PM
Passing Variables between Menus DwarF SageTV Studio 1 01-21-2006 05:42 PM


All times are GMT -6. The time now is 12:57 PM.


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