|
SYS-CON.TV Webcasts
Comments
Did you read today's front page stories & breaking news?
SYS-CON.TV
|
Top Links You Must Click On
Features A Thorough Subscription Model
Inverting the roles of responsibility in the event model in PowerBuilder
By: Jason Fenter
Nov. 15, 2010 08:00 AM
In PowerBuilder, an event is used as a place to put code in reaction to something. The .NET world uses events differently and, in my opinion, more appropriately. In .NET, an event is just notification that something happened. This lets other objects react to changes while PowerBuilder's events only let an object know about its own changes. Where is the benefit to the .NET approach? One of the most common scenarios is the master/detail window. The master view has a list of items and allows you to open a detail view for a specific item. How much work is done to update the master list once a detail item has been saved? What if you have a different window that uses that master list in a drop-down? How much work does it take to update that drop-down list when the detail window changes? The subscription model for .NET events makes it much easier. I'd like to share with you how I implemented that subscription model in PowerBuilder, applicable in versions six and later. What Is That?
Prerequisites Create a new custom nonvisual object and save it as "_hashtable". (I always start framework-level class names with an underscore.) Mark this object as autoinstantiated. Create a public instance string variable called is_Key as an unbound array. Create another of type any called ia_Value that is also an unbound array. The only other instance variable we need is a public long called Count. PUBLIC String is_Key[] We'll start with the ability to add things to the hashtable. We need a Put() method. Our Put() method needs two arguments: the key, which is a string, and the value which is of type Any. When we Put() something in the hashtable, we need to either update the value (if the key already exists) or add it anew. public subroutine put (String key, Any value) i = IndexOf (Key) is_Key[i] = Key end subroutine What is this IndexOf() method? That's how we find things in the hashtable when given a key. public function Long indexof (String key) FOR i = UpperBound (is_Key) TO 1 STEP -1 RETURN ll_Return end function Now we can find things and we can add things. Let's see about getting a value. public function any get (string key): Long i i = IndexOf (Key) RETURN la_Return end function Now let's remove an item. public function any remove (string key) SetNull (la_Return) IF i > 0 THEN RETURN la_Return We can add; we can remove; we can get a value. A hashtable has two other handy methods: KeyExists(), to see if something is there, and Clear(), to quickly clean it out. public function boolean keyexists (string key): RETURN (IndexOf (Key) > 0) public subroutine clear () is_Key = ls_Empty Don't forget to save and bask in the glory of having a simple hashtable in PowerBuilder! The Architecture
The last two may seem backwards to most people, but thinking of it in this way makes the code so much easier. Since articles and mailboxes are just string (the names of events), it makes our hashtable extremely useful. Our base object will basically have a hashtable containing mailboxes that are referenced by the article name. Each of these "mailbox" entries will itself be a hashtable of subscribers. When we publish an article, we'll grab a reference to each of the subscribing objects and use TriggerEvent() to pass notification. TriggerEvent() is the closest thing to a callback function that I can think of that's available in PowerBuilder. Let's Write Some Code! We'll start with adding a subscription. Since the publisher is storing all of the data, it makes sense to me to think of the publisher as being responsible for all of the actions. instead of a "SubscribeTo" name, I have an AddSubscription() method. Our AddSubscription() method takes three arguments: a reference to the object that is subscribing, the article to which it is subscribing, and the mailbox to which notification is sent. I'd like to make a note about that first argument, though.
We'll be passing in a reference to the calling object, so our argument type is "PowerObject", the base ancestor for all PowerBuilder classes. Any time you pass an object around that is not autoinstantiated, you're actually passing around a pointer to the object. That means that the scope of the argument applies to the pointer and not to the object it references. This is why you can pass in an object as "read only" and still modify the object's properties. In most instances when I want to pass an object reference into a function, I want to use the THIS keyword. The THIS keyword is a constant and constants must always be passed in as "read only." We have a read-only argument of type PowerObject that we'll call "Subscriber". We have a string argument called "Article" (which event on the publisher does the subscriber want to know about) and another string argument called "Mailbox" (the name of an event on the subscriber that we'll trigger when we publish the given article). Based on our architecture, our "Articles" is a hashtable that associates the name of an event with a collection of mailboxes. Each mailbox is a hashtable that associates the name of an event with the objects that use that event to receive notification. When we add a subscription, we look to see if anyone else has subscribed to that article. If so, we look to see if anyone else is using that mailbox. If so, we add the object reference to that collection (see Listing 1). Tell Me About It In all of this subscription service code, there are only two things that I am unsatisfied with. Because we lack callback functions, we have to pass data using the global Message object and the Message object can be rather volatile. The second thing that I am unsatisfied with is that we can't strongly type our event arguments. Despite this, we have an extremely usable subscription model and now that we have data, we're ready to publish! Publishing As you can see, we first check to see if anything has subscribed to the given article. If so, we loop through the assigned mailboxes. For each mailbox, we loop through the subscribers. We set the event data to the message object, then call the appropriate event on the subscriber. (The "mailbox" is the name of the event on the subscriber to call.) There's only one more method we need to add and we'll be done. For ease of use, let's overload the Publish() method so we only have to specify the article name. I find this useful when we don't need to supply any data for the event. public subroutine publish (string article) Put It to Use Start by inheriting from _EventProperties to create an object called ChangedEventData. On this object, add two string instance variables called OldValue and NewValue. Next, inherit from your base object to create an object called "Publisher_Example". Add a string instance variable called MyValue. Add an event to this object called "Changed" that has two arguments: OldValue of type string and NewValue of type string. Add a function to this object called "ChangeValue" that takes a single string argument. Here's the script for the ChangeValue() method: Public subroutine changevalue (string newvalue) MyValue = NewValue And in the Changed event, put this script: event changed (string OldValue, string NewValue) MyData.OldValue = OldValue Publish ("Changed", MyData) Inherit from your base object, this time creating an object called "Subscriber_Example". Add an event to this object called "On_PublisherChanged". In this event, put the following code: Event on_publisherchanged () MessageBox ("Changed", "The value was changed from " + RealEventData.OldValue + " to " + RealEventData.NewValue) To make it all work, our subscriber needs to subscribe to the publisher. On the Subscriber_Example object, add a method called SeeTheMagic(). That script should look like this: Public subroutine seethemagic() ExamplePublisher.ChangeValue ("Our first change!") Summary Reference
Reader Feedback: Page 1 of 1
Enterprise Open Source Magazine Latest Stories . . .
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
|
SYS-CON Featured Whitepapers
Most Read This Week |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||