So I was looking at the serialization classes
From
flicker-youtube@anduin.net@21:1/5 to
All on Tue Mar 2 08:50:25 2021
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"
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)