A new Synergy feature available with the recent 9.5.3 release is called I/O Statement Hooks. If you’ve read Richard Morris’ blog on the Synergex website, you may be familiar with it. Richard, being the biggest advocate of this feature, was instrumental in its design.
The IOHooks class can be used for many different purposes. As Richard puts it, the possibilities are endless. You can use it to replicate your Synergy data to a relational database, record transactions to a log file, encrypt and decrypt your data, or even log I/O when you want to debug your application. All of these and more can be done transparently, without changing a single line of code in your existing I/O routines.
To begin with, IOHooks was developed entirely as a SynergyDE class. Using it takes some OO experience, but developers without OO experience can easily take the template IOHooks class at the end of this article and extend it to do whatever they want. The IOHooks base class in the distribution contains a set of 17 virtual hook methods (9 pre-operation and 8 post-operation) and 4 constructors. To make use of IOHooks, all you have to do is create your own class that extends the IOHooks class, implements one or more constructors, and overrides one or more hook methods.
Then, in your application, you create an instance of your class, passing along the channel on which the file is open. That’s it! Now, any I/O operation that you’ve hooked (FIND, READ, READS, STORE, WRITE, WRITES, DELETE, UNLOCK, CLOSE) will first call and execute your pre-operation hook method (if you have one). Immediately after your method exits, the I/O operation is issued. Then, following the I/O, your post-operation hook method (if you have one) is called and executed. And once your post-operation hook exits, your application resumes.
What you do inside your pre- and post-operation hook methods is what adds the substance to this feature. In pre-operation WRITES, your hook method will have access to the record buffer before it’s written. In post-operation READS, your hook method will have access to the record buffer after it’s been read and before your application gets it. Add some encryption logic to your pre-hook code and decryption logic to your post-hook code, and you’ve now seamlessly employed encryption in your file. Add logic to your post-write methods to log updates to a file. Add a debugging option that dynamically enables a debug IOHook class to keep track of record locks. As you can see, the possibilities go on and on.
But to truly understand how easy using IOHooks is, you need to see some sample code. Here’s a simple code example of an IOHooks class that reads through the Synergy message file, syntxt.ism. I’ve hooked the post-operation READS statement and, just for fun, added logic to suppress the error mnemonic by replacing it with dots.
import Synergex.SynergyDE.Select
import Synergex.SynergyDE.IOExtensions
namespace myns
class myhooks extends IOHooks
public method myhooks
in channel, n
parent(channel)
proc
endmethod
public override method reads_post_operation_hook, void
inout buffer, a
in optional out_rfa, a
in flags, IOFlags
inout error, int
proc
buffer(9:10) = " ........ " ;Replace mnemonic
endmethod
endclass
endnamespace
main
record
rec, a218
proc
open(15, o, 'tt:')
open(1, u:i, "DBLDIR:syntxt")
(void)new myhooks(1) ;Hook channel 1
repeat
begin
reads(1, rec, eof)
writes(15, %atrim(rec))
end
eof,
close 1
stop
The main application logic in this example just sees the record as the hook method presents it ¬ it’s none the wiser. Also, the myhooks class is just a snippet of the overall IOHooks template provided below. All I’ve done is add a single line to the READS method; the rest of the class template can be used as is.
The above example shows what you can do with one I/O statement and one direction. You might want to develop a class that hooks each I/O operation and both directions and then enable and disable them dynamically. You can even hook a Select class and intercept records as they’re retrieved. The possibilities are truly endless.
As you can see, I/O Statement Hooks can be a useful tool. Just remember, once your methods are hooked to a channel, they’ll be executed on every matching I/O. You don’t want excessive logic to bog down your application, so keep your hook methods simple and efficient.
Here is the IOHooks template that’s discussed above:
import Synergex.SynergyDE.Select
import Synergex.SynergyDE.IOExtensions
namespace hooks
class hooks_template extends IOHooks
public method hooks_template
in channel, n
in premask, IOEventMask
in postmask, IOEventMask
parent(channel, premask, postmask)
proc
endmethod
public method hooks_template
in channel, n
parent(channel)
proc
endmethod
public method hooks_template
in from, @From
parent(from)
proc
endmethod
method ~hooks_template
proc
endmethod
public override method find_pre_operation_hook, void
mismatch in optional key, n
in optional in_rfa, a
in optional keynum, n
in flags, IOFlags
proc
endmethod
public override method read_pre_operation_hook, void
mismatch in optional key, n
in optional in_rfa, a
in optional keynum, n
in flags, IOFlags
proc
endmethod
public override method reads_pre_operation_hook, void
in flags, IOFlags
proc
endmethod
public override method write_pre_operation_hook, void
inout buffer, a
in optional recnum, n
in optional out_rfa, a
in flags, IOFlags
proc
endmethod
public override method writes_pre_operation_hook, void
inout buffer, a
in flags, IOFlags
proc
endmethod
public override method store_pre_operation_hook, void
inout buffer, a
in flags, IOFlags
proc
endmethod
public override method delete_pre_operation_hook, void
proc
endmethod
public override method unlock_pre_operation_hook, void
in optional rfa, a
in flags, IOFlags
proc
endmethod
public override method close_pre_operation_hook, void
in flags, IOFlags
proc
endmethod
public override method find_post_operation_hook, void
mismatch in optional key, n
in optional out_rfa, a
in optional keynum, n
in flags, IOFlags
inout error, int
proc
endmethod
public override method read_post_operation_hook, void
inout buffer, a
mismatch in optional key, n
in optional out_rfa, a
in optional keynum, n
in flags, IOFlags
inout error, int
proc
endmethod
public override method reads_post_operation_hook, void
inout buffer, a
in optional out_rfa, a
in flags, IOFlags
inout error, int
proc
endmethod
public override method write_post_operation_hook, void
inout buffer, a
in optional recnum, n
in optional out_rfa, a
in flags, IOFlags
inout error, int
proc
endmethod
public override method writes_post_operation_hook, void
inout buffer, a
in optional out_rfa, a
in flags, IOFlags
inout error, int
proc
endmethod
public override method store_post_operation_hook, void
inout buffer, a
in optional stored_rfa, a
in flags, IOFlags
inout error, int
proc
endmethod
public override method delete_post_operation_hook, void
inout error, int
proc
endmethod
public override method unlock_post_operation_hook, void
in flags, IOFlags
inout error, int
proc
endmethod
endclass
endnamespace
For more information about the IOHooks class, see Synergex.SynergyDE.IOExtensions.IOHooks in chapter 9 of the Synergy Language Reference Manual.