Comments
Matt McLarty wrote: For more info... Follow me on Twitter See our website
Cloud Expo on Google News


2008 West
DIAMOND SPONSOR:
Data Direct
SOA, WOA and Cloud Computing: The New Frontier for Data Services
PLATINUM SPONSORS:
Red Hat
The Opening of Virtualization
GOLD SPONSORS:
Appsense
User Environment Management – The Third Layer of the Desktop
Cordys
Cloud Computing for Business Agility
EMC
CMIS: A Multi-Vendor Proposal for a Service-Based Content Management Interoperability Standard
Freedom OSS
Practical SOA” Max Yankelevich
Intel
Architecting an Enterprise Service Router (ESR) – A Cost-Effective Way to Scale SOA Across the Enterprise
Sensedia
Return on Assests: Bringing Visibility to your SOA Strategy
Symantec
Managing Hybrid Endpoint Environments
VMWare
Game-Changing Technology for Enterprise Clouds and Applications
Click For 2008 West
Event Webcasts

2008 West
PLATINUM SPONSORS:
Appcelerator
Get ‘Rich’ Quick: Rapid Prototyping for RIA with ZERO Server Code
Keynote Systems
Designing for and Managing Performance in the New Frontier of Rich Internet Applications
GOLD SPONSORS:
ICEsoft
How Can AJAX Improve Homeland Security?
Isomorphic
Beyond Widgets: What a RIA Platform Should Offer
Oracle
REAs: Rich Enterprise Applications
Click For 2008 Event Webcasts
SYS-CON.TV
Top Links You Must Click On


A Thorough Subscription Model
Inverting the roles of responsibility in the event model in PowerBuilder

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?
There's a plethora of articles on subscription models, and almost all of them use the analogy of a magazine. It works, so why should I break the mold? Here's a list of terms that I'll be using throughout this article:

  • Subscription: The desire to receive notification when an event happens.
  • Subscriber: The object that actually receives the notification.
  • Publisher: The object on which the event happens.
  • Article: The name of the event on the publisher to which the subscriber wishes to subscribe.
  • Mailbox: The mailbox basically is how the publisher will deliver the notification to the subscriber.
  • Publish: The act of providing notification to the subscriber.

Prerequisites
Probably the one thing that I miss most in PowerBuilder is a hashtable. PB.NET gives you access to that, but many of us are on previous versions. Here's a quick-and-dirty implementation that allows you to store any object and reference it using a string value.

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[]
PUBLIC Any ia_Value[]
PUBLIC Long Count

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)
Long    i

i = IndexOf (Key)
IF i = 0 THEN
i = UpperBound (is_Key) + 1
Count ++
END IF

is_Key[i] = Key
ia_Value[i] = Value

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)
Long    i, ll_Return = 0

FOR i = UpperBound (is_Key) TO 1 STEP -1
IF is_Key[i] = Key THEN
ll_Return = i
EXIT // No point in continuing to look...
END IF
NEXT

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
Any     la_Return
SetNull (la_Return)

i = IndexOf (Key)
IF i > 0 THEN la_Return = ia_Value[i]

RETURN la_Return

end function

Now let's remove an item.

public function any remove (string key)
Any     la_Return
Long i

SetNull (la_Return)
i = IndexOf (Key)

IF i > 0 THEN
la_Return = Get (Key)
SetNull (is_Key[i])
SetNull (ia_Value[i])
Count --
END IF

RETURN la_Return
end function

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)
end function

public subroutine clear ()
String  ls_Empty[]
Any     la_Empty[]

is_Key = ls_Empty
ia_Value = la_Empty
Count = 0
end subroutine

Don't forget to save and bask in the glory of having a simple hashtable in PowerBuilder!

The Architecture
Our publisher will be keeping track of all of our subscription information. My personal line of thought is:

  • What articles have been subscribed to?
  • For each article, what are the mailboxes that I'll be delivering notification to?
  • What objects are using each mailbox for delivery?

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!
Open up your base nonvisual object. (You do have one, right? If not, create one. Mine is called "_nonvisualobject".) Add a private instance variable of type "_hashtable" and call it "Articles". This is where we'll store all of our subscription data.

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
Now that we can add a subscription, we need to be able to publish our articles. In .NET, events have arguments so that you not only know that something happened but you also know what happened. We need a generic "properties" object that we can descend from later and use for passing data. In a generic situation, there's only one piece of information that we have available: a reference to the publishing object. Create a custom nonvisual object and add a public instance variable of type "PowerObject" to it. Call this instance variable PublishingObject for clarity. When I saved this object, I called it "_eventproperties". This object should not be autoinstantiated.

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
Our base object needs a Publish() method with two arguments: the name of the article being published and an object of type _eventproperties containing the data for the event. In this method, we'll set the reference to the publishing object, then look for any subscribers that have subscribed to the given article and send notification to them (see Listing 2).

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)
_EventProperties EmptyProperties
Publish (Article, EmptyProperties)
end subroutine

Put It to Use
That's not really a lot of work. We added two new objects: a hashtable and a generic "event properties" object. And we added one instance variable and three methods to our base object. Now let's see how easy it is to use this. For our example, we're going to have an object that "changes." When it "changes," it will publish a "Changed" event, providing the old and the new values. We'll also have an object that subscribes to this event.

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)
String OldValue
OldValue = MyValue
IF IsNull (OldValue) THEN OldValue = "[NULL]"

MyValue = NewValue
THIS.EVENT Changed (OldValue, NewValue)
End subroutine

And in the Changed event, put this script:

event changed (string OldValue, string NewValue)
ChangedEventData MyData
MyData = CREATE ChangedEventData

MyData.OldValue = OldValue
MyData.NewValue = NewValue

Publish ("Changed", MyData)
End event

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 ()
ChangedEventData RealEventData
RealEventData = Message.PowerObjectParm

MessageBox ("Changed", "The value was changed from " + RealEventData.OldValue + " to " + RealEventData.NewValue)
End event

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()
Publisher_Example ExamplePublisher
ExamplePublisher = CREATE Publisher_Example
ExamplePublisher.AddSubscription (THIS, "Changed", "On_PublisherChanged")

ExamplePublisher.ChangeValue ("Our first change!")
ExamplePublisher.ChangeValue ("Oops, I did it again.")
End subroutine

Summary
What did we do here? Basically, we've inverted the roles of responsibility in the event model in PowerBuilder. Now, when one object is dependent on a second object, the first object can say, "What do I need to do when that other object's state changes?" We've realigned our thinking to closer match .NET, thus easing our migration in the future. And we've better encapsulated our scope of responsibility because the publishing object doesn't need to know anything about any other object that might be using it. What can we do with this? If we have a list of things in memory (the "C" in an "MVC" [1] design pattern), then any window can subscribe to a change event and update itself automatically. If we have a nonstandard user input device (like an RS232 barcode scanner or credit card scanner), we can add a subscription for when data is received. Or... I'll leave it up to the reader to come up with new ways to use this.

Reference

  1. The Model-View-Controller pattern hinges on a clean separation of objects into one of three categories - models for maintaining data, views for displaying all or a portion of the data, and controllers for handling events that affect the model or view(s). See also http://en.wikipedia.org/wiki/Model-View-Controller.
About Jason Fenter
Jason Fenter is an independent consultant working with PowerBuilder since 1996. With experience ranging from large companies with teams of ten or more to private companies with a single person for the IT department – and with projects ranging from inventory management to customer tracking to finance – Jason has an extensive background and knowledge base to draw upon.

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Enterprise Open Source Magazine Latest Stories . . .
Cloud computing is creating the new Wall Street boom, according to NIA. The only industry that is as bright as cloud computing on Wall Street is social networking, NIA said in a recent report. 2012 will be known as the year cloud computing became widely adopted worldwide. Cloud comput...
The impact of Big Data is extremely broad for business, information management and technology. Being able to analyze your growing mountain of data can give you a distinct competitive advantage, but Big Data can be more than traditional tools can handle. In his session at the 10th Int...
In this CTO Power Panel at the 10th International Cloud Expo, moderated by Cloud Expo Conference Chair Jeremy Geelan, industry-leading CTOs & VPs of Technology will discuss such topics as: Which do you think is the most important cloud computing standard still to tackle? Who should...
China’s antitrust regulators gave Google’s $12.5 billion acquisition of Motorola Mobility the nod Saturday provided Google’s Android operating system remains open and free-of-charge for the next five years. The “free” stipulation apparently doesn’t apply to applications or services...
If your organization already uses virtualized infrastructure, you are well on your way to providing IT as a Service. But as businesses demand faster results in today’s competitive market, organizations look to gain more benefits from cloud computing than just virtualized infrastructure...
Citrix has acquired Virtual Computer, a little Massachusetts outfit with enterprise-scale management solutions for client-side virtualization. It means to combine the acquisition’s NxTop widgetry with its XenClient hypervisor to create a new Citrix XenClient Enterprise edition that c...
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


SYS-CON Featured Whitepapers
ADS BY GOOGLE