• 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)
  • From JL Turriff@21:1/5 to All on Wed Jun 2 06:02:35 2021
    When I try to run this I get an error:

    $ rexx SerializedRexxObjectClass
    878 *-* ::requires "bankaccount.cls"
    Error 43 running /home/leslie/bin/rexx/SerializedRexxObjectClass line 878: Routine not found.
    Error 43.901: Could not find file "bankaccount.cls" for ::REQUIRES. @07:25:20,leslie@pinto rc=213

    It looks to me like the file might need to be broken into several pieces, but it's not clear where the breaks should be.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jean-Louis Faucher@21:1/5 to jltu...@gmail.com on Wed Jun 2 06:46:21 2021
    On Wednesday, June 2, 2021 at 3:02:36 PM UTC+2, jltu...@gmail.com wrote:
    When I try to run this I get an error:

    $ rexx SerializedRexxObjectClass
    878 *-* ::requires "bankaccount.cls"
    Error 43 running /home/leslie/bin/rexx/SerializedRexxObjectClass line 878: Routine not found.
    Error 43.901: Could not find file "bankaccount.cls" for ::REQUIRES. @07:25:20,leslie@pinto rc=213

    It looks to me like the file might need to be broken into several pieces, but it's not clear where the breaks should be.

    rto.cls : cut before the comment Bank Account Demo
    bankaccount.cls : cut after the class BankCustomer
    test_ckass.rex : the rest

    I stopped the demo when the ledger became > 600 :-)
    A file serialized.txt was generated.
    The serialization of MyBankAcct is only on day 10.
    At each run, a new line is added to serialize.txt.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From flicker-youtube@anduin.net@21:1/5 to Jean-Louis Faucher on Thu Jun 3 05:17:58 2021
    sounds about right... it was a little demo.

    On Wednesday, 2 June 2021 at 14:46:22 UTC+1, Jean-Louis Faucher wrote:
    On Wednesday, June 2, 2021 at 3:02:36 PM UTC+2, jltu...@gmail.com wrote:
    When I try to run this I get an error:

    $ rexx SerializedRexxObjectClass
    878 *-* ::requires "bankaccount.cls"
    Error 43 running /home/leslie/bin/rexx/SerializedRexxObjectClass line 878: Routine not found.
    Error 43.901: Could not find file "bankaccount.cls" for ::REQUIRES. @07:25:20,leslie@pinto rc=213

    It looks to me like the file might need to be broken into several pieces, but it's not clear where the breaks should be.
    rto.cls : cut before the comment Bank Account Demo
    bankaccount.cls : cut after the class BankCustomer
    test_ckass.rex : the rest

    I stopped the demo when the ledger became > 600 :-)
    A file serialized.txt was generated.
    The serialization of MyBankAcct is only on day 10.
    At each run, a new line is added to serialize.txt.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)