Technique #2: partitioning non-visual logic via NVOs

Partitioning non-visual logic and encapsulating it within PowerBuilder NVOs has been a long-time best practice among PowerBuilder developers. What's relatively new, however, is utilizing middleware or application server, such as Microsoft IIS, IBM WebSphere*, Oracle WebLogic*, TmaxSoft JEUS*, or JBoss* to deploy these NVOs to the server (i.e. server-side NVOs) and invoke them from the client over IIOP or HTTP.

* Requires an SAP Sybase plug-in that is purchased separately from SAP or authorized resellers.

To give you a better idea of what this looks like, the following diagram shows a very high-level architecture of PowerBuilder applications utilizing server-side NVOs when deployed as a Windows Client/Server application as well as an n-tier Web (.NET* or J2EE) application with Appeon PowerServer.

Figure 8. Architecture with server-side NVOs

Architecture with server-side NVOs

Deploying your non-visual logic as server-side NVOs is an excellent way to boost the performance of your application over a WAN; however, some thought must be given as what to partition. On one hand, consolidating your business logic within NVOs will significantly thin out client-side processing and move all those server call-inducing statements to the server-side running in a low-latency LAN environment. On the other hand, each invocation of the server-side NVO is a server call in itself.

If the non-visual logic you are partitioning contains multiple statements that result in server calls, then this would be a good candidate. However, if your non-visual logic does not contain any statements that would result in server calls, then by partitioning this you have not only created more work for yourself but actually added an additional server call that didn't exist before. So unfortunately it's not as simple as moving all non-visual logic to the server-side.

Imagine your PowerBuilder client contains the following code:

long ll_id

dw_1.Retrieve()
dw_1.SetSort("#1 A, #2 D")
dw_1.Sort()

declare order_detail cursor for 
select id from order_detail where orderid = :arg_orderid;
open order_detail;
fetch order_detail into :ll_id;

do while sqlca.sqlcode = 0
	update order_detail set price = price*1.2
	where orderid = :arg_orderid and id = :ll_id; 

	if sqlca.sqlcode < 0 then
		rollback;
		return
	end if
	
	fetch order_detail into :ll_id;
loop
close order_detail;
commit;

dw_2.Retrieve()
dw_2.SetFilter("price >= 100")
dw_2.Filter()

The code in bold above would be good candidate for partitioning as server-side NVOs while the rest of the code should remain at the PB client. After partitioning this logic, the new PB client code, which would invoke the server-side NVO, would be as follows:

n_order ln_order
long ll_rc

dw_1.Retrieve()
dw_1.SetSort("#1 A, #2 D")
dw_1.Sort()

ll_rc = myconnect.CreateInstance(ln_order, "PB_pkg_1/n_order")
if ll_rc = 0 then
    ln_order.of_UpdateOrderPrice(arg_orderid)
end if

dw_2.Retrieve()
dw_2.SetFilter("price >= 100")
dw_2.Filter()

With this technique we have reduced those numerous server calls of the database transaction to just one single call to the NVO, and at the same time created a re-usable component that can be shared by other modules in our PowerBuilder application or shared by other applications.