flicker...@anduin.net
unread,Mar 2, 2021, 11:50:26 AM3/2/21You do not have permission to delete messages in this group
Sign in to report message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to
So I was looking at serialization classes ....
and I had some issues with the classes provided
so I wrote something which would serialize any class
serialized rexx object class
/*
Serializer
*/
::Class SerializeHandler public
::constant code
::attribute classHandled
::attribute seperator private
::constant sepcode "!"
::attribute dataEncodeMethod
::attribute dataDecodeMethod
::constant seperatorwordpos 1
::constant commandwordpos 2
::constant idwordpos 3
::constant datawordpos 4
::Method serialize public
use arg object, helper
return self~serializer(object, helper)
::method deserialize public
use arg data, helper
return self~deserializer(data, helper)
::method Accepts
use arg classQuery
response = .false
if classQuery~class = self~classHandled then response = .true
return response
::method AcceptsCommand
use arg command
if command = self~code then response = .true
else response = .false
return response
::method setSepcode
use arg helper
self~seperator = self~sepcode || helper~referencesBag~items()
return self~seperator
::method endcode
return self~code||"END"
::method getSeperator
use arg data
select
when data~class = .RTOSerializeService then do
returnobject = self~setSepcode(data)
end
otherwise do
returnobject = data~word(self~seperatorwordpos)
end
end
return returnobject
::method getElements
use arg data
delim = self~getSeperator(data)
elem = .array~new()
do i = 0 by 1 while data <> ''
parse var data w.i (delim) data
elem~insert(w.i)
end
return elem
::method makeObjectClassHandled
o = self~classHandled~new()
return o
/* abstract methods */
::method serializer abstract
/* abstract methods */
::method deserializer abstract
::Class ArraySerializeHandler subclass SerializeHandler public
::constant code ARR
::constant sepcode "|"
::method init
self~classHandled = .Array
::method serializer
use arg object, helper
currentseperator = self~getSeperator(helper)
data = self~code helper~id(object) object~items
do i = 1 to object~items
data = data currentseperator helper~runSerializer(object~at(i))
end
data = currentseperator data currentseperator self~endcode helper~id(object)
return data
::method deserializer
use arg object, helper
ArraySize = object~word(4)
ArrayReturnObject = .Array~new(ArraySize)
findcode = self~endcode helper~getserializedID(object)
parse var object object (findcode) junk
elements = self~getElements(object)
/* object being registered and the string which caused it to be registered
from which we will work out what the ID which is being used is going to be
*/
helper~deserializedObjectReferencesDirectory~put(ArrayReturnObject,object~word(3))
do e over elements~allitems
if e <> .nil & e <> "" then do
o = helper~runDeserializer(e)
ArrayReturnObject~append(o)
end
end
return o
::Class LikeArraySerializeHandler subclass SerializeHandler public
::method serializer
use arg object, helper
helper~addReference(object)
currentseperator = self~getSeperator(helper)
items = object~makeArray
data = currentseperator self~code helper~id(object) items~items
do i = 1 to items~items
if object~at(items~at(i)) <> .nil then do
data = data currentseperator helper~runSerializer(object~at(items~at(i)))
end
end
data = data currentseperator self~endcode helper~id(object)
return data
::method deserializer
use arg object, helper
ro = self~classHandled~new()
parse var object object (findcode) junk
elements = self~getElements(object)
/* object being registered and the string which caused it to be registered
from which we will work out what the ID which is being used is going to be
*/
helper~deserializedObjectReferencesDirectory~put(ro,object~word(3))
do i over elements~allindexes
e = elements~at(i)
o = helper~runDeserializer(e)
if o~class <> .Object then do
ro~put(o,i)
end
end
return o
::Class BagSerializeHandler subclass LikeArraySerializeHandler public
::constant code BAG
::constant sepcode "^"
::method init
self~classHandled = .Bag
::method deserializer
use arg object, helper
ro = self~classHandled~new()
parse var object object (findcode) junk
elements = self~getElements(object)
/* object being registered and the string which caused it to be registered
from which we will work out what the ID which is being used is going to be
*/
helper~deserializedObjectReferencesDirectory~put(ro,object~word(3))
do i over elements~allindexes
e = elements~at(i)
o = helper~runDeserializer(e)
if o~class <> .Object then do
ro~put(o,o)
end
end
return ro
::Class DirectorySerializeHandler subclass LikeArraySerializeHandler public
::constant code DIR
::constant sepcode "*"
::method init
self~classHandled = .Directory
::Class ListSerializeHandler subclass LikeArraySerializeHandler public
::constant code LIS
::constant sepcode "*"
::method init
self~classHandled = .List
::Class StringSerializeHandler subclass SerializeHandler public
::constant code STR
::method init
self~classHandled = .String
::method serializer
use arg object, helper
currentseperator = self~getSeperator(helper)
helper~addReference(object)
return currentseperator self~code helper~id(object) object~encodeBase64
::method deserializer
use arg object, helper
/* RO = self~makeObjectClassHandled() */
RO = object~word(self~datawordpos)~decodeBase64
/* object being registered and the string which caused it to be registered
from which we will work out what the ID which is being used is going to be
*/
helper~deserializedObjectReferencesDirectory~put(RO,object~word(2))
return RO
::Class ExternalClassSerializeHandler subclass SerializeHandler public
::constant code VAL
::constant sepcode ":"
::constant commandwordpos 2
::constant seperatorwordpos 1
::method serializer
use arg objectToInspect, helper
currentseperator = self~getSeperator(helper)
serializedata = ""
classOfObjectInspected = objectToInspect~class()
allClassesToBeInspected = helper~reverseList(helper~findSubclasses(classOfObjectInspected, .list~new()))
serializedata = currentseperator "OBJ" helper~id(objectToInspect) helper~classname(objectToInspect) helper~id(classOfObjectInspected) helper~classname(classOfObjectInspected) currentseperator
methodProvider = .relation~new
do classToCheck over allClassesToBeInspected
methodProvider = helper~findMethodsAndProviders(classToCheck, methodProvider)
end
do classToCheck over allClassesToBeInspected
if classToCheck~package~name="REXX" then do
nop
end
else
do
serializedata = serializedata currentseperator "SUBC" helper~id(objectToInspect) helper~classname(classToCheck) helper~id(classToCheck) currentseperator
methodsinClass = methodProvider~allAt(classToCheck)
serializedata = serializedata "CODE" helper~id(objectToInspect) helper~classname(objectToInspect) currentseperator
do method over methodsinClass
if helper~hasSource(classToCheck, method) = .true then do
source = helper~getSource(classToCheck, method)
serializedata = serializedata "SRC" helper~id(objectToInspect) method helper~classname(classToCheck) helper~id(classToCheck) helper~runSerializer(source~makeString) currentseperator
end
end
serializedata = serializedata "CODEEND" helper~id(objectToInspect) currentseperator
serializedata = serializedata "ATTR" helper~id(objectToInspect) helper~classname(objectToInspect) currentseperator
do method over methodsinClass
if helper~hasSource(classToCheck, method) = .false then do
if method <> "INIT" then do
if helper~isSettor(method) = .false then do
AttrValue = objectToInspect~sendWith(method,.Array~new)
serializedata = serializedata self~code helper~id(objectToInspect) method helper~runSerializer(AttrValue) currentseperator
end
end
end
end
end
end
serializedata = serializedata "ATTREND" helper~id(objectToInspect) currentseperator
return serializedata "OBJEND" helper~id(objectToInspect)
::method AcceptsCommand
use arg command
select
when command = self~code then response = .true
when command = "OBJ" then response = .true
when command = "CODE" then response = .true
when command = "ATTR" then response = .true
when command = "SRC" then response = .true
when command = "SUBC" then response = .true
otherwise response = .false
end
return response
::method makeObjectClassHandled
return .nil
::method Accepts
use arg classQuery
response = .true
if classQuery~class~package~name="REXX" then response = .false
return response
::method deserializer
use arg object, helper
findcode = self~endcode helper~getserializedID(object)
parse var object object (findcode) junk
elements = self~getElements(object)
ReturnObject = .Object~new
/* object being registered and the string which caused it to be registered
from which we will work out what the ID which is being used is going to be
*/
/* helper~registerDeserializedObject(ReturnObject, elements~at(2)) */
/* remove item from the list of elements */
ValuesToSet = .Directory~new
parentClass = .object
do e over elements~allitems
if e <> .nil & e <> "" then do
command = e~word(1)
id = e~word(2)
methodorclass = e~word(3)
select
when command = "OBJ" then do
ReturnObject=.object~subClass(methodorclass)~new()
helper~deserializedObjectReferencesDirectory~put(ReturnObject,id)
end
when command = "SUBC" then do
parentClass = parentClass~class~subclass(e~word(3))
end
when command = "SRC" then do
parse var e word1 word2 word3 word4 word5 rest
methodname = methodorclass
src = helper~runDeserializer(rest)
src = src~changestr(x2c("0A"),";")
mymethod= .method~new("",src)
returnObject~class~define(methodname,mymethod)
end
when command = "VAL" then do
ReturnObject~class~subclass(parentClass~class~id)
parse var e word1 word2 word3 rest
o = helper~runDeserializer(rest)
helper~deserializedObjectReferencesDirectory~put(o,id)
variabletosend = .Array~new
variabletosend~append(o)
/* create settor */
methodname = methodorclass||"="
src = .Array~new
src~append("expose "||methodorclass)
src~append("use arg "||methodorclass)
mymethod= .method~new("",src)
ReturnObject~class~define(methodname,mymethod)
ValuesToSet~put(variabletosend, methodname)
/* create getter */
methodname = methodorclass
src = .Array~new
src~append("expose "||methodorclass)
src~append("return "||methodorclass)
mymethodA = .method~new("",src)
ReturnObject~class~define(methodname,mymethodA)
ReturnObject= ReturnObject~class~subclass(ReturnObject~class~id)~new
end
otherwise do
end
end
end
end
/* Set Values */
sindexes = ValuesToSet~Supplier~allIndexes
sitems = ValuesToSet~Supplier~allItems
do i = 1 to sindexes~items
index = sindexes~at(i)
v = sitems~at(i)
returnObject~send(index,v)
end
return ReturnObject
/*
Because one needs a service
*/
::CLASS RTOSerializeService public
::attribute SerializeHandlers
::attribute referencesBag
::attribute SerializeSource
::attribute deserializedObjectReferencesDirectory
::METHOD INIT public
self~SerializeHandlers= .list~new()
self~register(.StringSerializeHandler~new())
self~register(.ArraySerializeHandler~new())
self~register(.BagSerializeHandler~new())
self~register(.DirectorySerializeHandler~new())
self~register(.ListSerializeHandler~new())
self~register(.ExternalClassSerializeHandler~new())
self~reset
::method register
use arg obj
sh = self~SerializeHandlers()
sh~insert(obj, sh~last)
::method reset
self~referencesBag=.bag~new
self~deserializedObjectReferencesDirectory = .Directory~new
::method Serialize public
use arg object
returned = self~runSerializer(object)
self~reset()
return returned
::method runSerializer
use arg objectBeingInspected
serializedata = "REF" self~id(objectBeingInspected)
if self~hasReference(objectBeingInspected) = .false then do
self~addReference(objectBeingInspected)
do handler over self~SerializeHandlers
if handler~Accepts(objectBeingInspected) = .true then do
serializedata = handler~serialize(objectBeingInspected, self)
end
end
end
return serializedata
::method Deserialize public
use arg input
output = self~runDeserializer(input)
self~reset()
return output
::method runDeserializer
use arg input
output = .Object~new
if input~word(1) = "REF" then do
output = self~deserializedObjectReferencesDirectory~at(input~word(2))
self~deserializedObjectReferencesDirectory~put(output, input~word(2))
end
else
do handler over self~SerializeHandlers
command = input~word(handler~commandwordpos)
if handler~AcceptsCommand(command) = .true then do
output = handler~deserialize(input, self)
self~deserializedObjectReferencesDirectory~put(output, input~word(3))
output = self~deserializedObjectReferencesDirectory~at(input~word(3))
end
end
return output
/*
Recursively find subclasses
*/
::method findSubclasses
use arg classtoFind, list
if classToFind <> .nil then do
/* put it in the list if it isn't */
if list~hasitem(classtoFind) = .false then do
list~insert(classtoFind,list~last)
end
self~findSubclasses(classtoFind~superclass, list)
end
return list
/*
find methods against each class
*/
::method findMethodsAndProviders
use arg classtosearch, methodRel
foundMethods = classtosearch~methods(classtosearch)
do while foundMethods~available
methodfound = foundMethods~index
methodRel[classtosearch] = methodfound
foundMethods~next
end
return methodRel
::method addReference
use arg obj
self~referencesBag~put(obj)
::method hasReference
use arg obj
return self~referencesBag~hasitem(obj)
/*
Does it have source code
*/
::method hasSource
use arg classToInspect, MethodName
hasSource = .false
if classToInspect~hasMethod(MethodName) = .false then do
source = self~getSource(classToInspect, MethodName)
if source~isEmpty() then hasSource = .false
else hasSource = .true
end
return hasSource
::method getSource
use arg classToInspect, MethodName
source = classToInspect~method(MethodName)~source
return source
/* provide class name */
::method className
use arg object
return object~defaultname~word(2)
/* provide ID */
::method id
use arg object
return object~identityHash
/*
The ID in the serialized form
*/
::method getserializedID
use arg object
return object~word(2)
::method isSettor
use arg object
response = .false
if object~pos("=") > 1 then response = .true
return response
::method registerDeserializedObject
use arg object, serializedForm
id = self~getserializedID(serializedForm)
self~deserializedObjectReferencesDirectory~put(object,id)
::method reverselist
use arg Inputlist
/* Reverse the list order */
OutputList = .list~new()
do until Inputlist~isEmpty
OutputList~append(Inputlist~lastItem)
Inputlist~remove(Inputlist~last)
end
return OutputList
bank account cls
/*
Bank Account Demo
*/
::class bankaccount subclass object public
::attribute balance
::attribute interestrate
::attribute waittime
::attribute feesToBeCharged
::attribute transactionFee
::attribute accountActive
::attribute daySinceOpen
::attribute ledger
::attribute AccountHolder
::constant SecretCode 299792458
::method init public
self~ledger = .Array~new()
self~waittime = 3
self~AccountHolder = .Directory~new
::method openAccount public
use arg initialDeposit
self~balance = 0
self~feesToBeCharged = 0 /* First one is free .. how generous */
self~interestrate = 0.00127
self~transactionFee = 2.50
self~accountActive = .true
say "Account opened"
self~daySinceOpen = 0
self~transaction(initialDeposit)
::method addInterest public
interest = trunc(self~balance * self~interestrate,2)
self~recordTransaction(interest)
self~balance = self~balance + interest
::method transaction public
use arg amount
self~recordTransaction(amount)
self~balance = self~balance + amount
self~feesToBeCharged = self~feesToBeCharged + self~transactionFee
say "did transaction for" amount "balance" self~balance "and fees due" self~feesToBeCharged
::method chargeFees public
self~balance = self~balance - self~feesToBeCharged
say "Fees charged" self~feesToBeCharged
self~recordTransaction(self~feesToBeCharged)
self~feesToBeCharged = 0
::method recordTransaction
use arg amount
self~ledger~append(amount)
::method nukeWorld public
use arg secretcode
say "you have accidentally pressed the button and destroyed the world"
return
::method LinkAccountHolder public
use arg CustomerToLink
self~AccountHolder~put(CustomerToLink,CustomerToLink~name)
say self~AccountHolder~items
CustomerToLink~account~put(self)
::class SavingsAccount subclass bankaccount public
::method openAccount public
use arg initialDeposit
/* super it first */
self~openAccount:super(initialDeposit)
/* then change some settings */
self~interestrate = 0.00427
self~transactionFee = 5.50
::class SuperSavingsAccount subclass SavingsAccount public
::method openAccount public
use arg initialDeposit
/* super it first */
self~openAccount:super(initialDeposit)
/* then change some settings */
self~interestrate = 0.00427
self~transactionFee = 5.50
::class BankCustomer public subclass object
::attribute name public
::attribute address public
::attribute account public
::method init public
self~account = .bag~new
test ckass
/*
*/
use arg fn
SerializeService = .RTOSerializeService~new()
if fn <> "FN" then do
data = linein(fn)
data = SerializeService~Deserialize(DATA)
say data~balance
say data~AccountHolder~items
say data~ledger~items
end
else
do
MyBankAcct = .SuperSavingsAccount~new()
/*
It's something external
*/
maxtransactionstorun = random(3,7)
i = 1
BobBobskin= .BankCustomer~new()
BobBobskin~name="Bob Bobskin"
MyBankAcct~LinkAccountHolder(BobBobskin)
Dashinka = .BankCustomer~new()
Dashinka~name="Dashika Doodie"
Dashinka~address = "1234 street"
MyBankAcct~LinkAccountHolder(Dashinka)
SerializeService~SerializeSource = .true
a = SerializeService~Serialize(Dashinka)
b = SerializeService~deserialize(a)
SerializeService~RESET
do forever
if MyBankAcct~accountActive = .true then do
say MyBankAcct~accountActive
MyBankAcct~daySinceOpen = MyBankAcct~daySinceOpen + 1
say "On day" i "Account Open for" MyBankAcct~daySinceOpen "Days, Balance" MyBankAcct~balance
MyBankAcct~addInterest()
/* Run a random number of transactions */
do j = 1 to RANDOM(5)
MyBankAcct~transaction(RANDOM(-10,10))
end
i = i + 1
if (MyBankAcct~daySinceOpen // 7) = 0 then MyBankAcct~chargeFees
say "ledger has" MyBankAcct~ledger~items()
say copies("-",20)
if i = 10 then do
data = SerializeService~Serialize(MyBankAcct)
rc = lineout("serialized.txt",data)
SerializeService~reset
end
end
else do
if random(0,5) = 1 then do
MyBankAcct~openAccount(100)
end
end
say "waiting" i
call SysSleep(MyBankAcct~waittime)
end
end
::requires "rto.cls"
::requires "bankaccount.cls"