Dynamic Web Development with Seaside

25.2Object Serialization

A variation on the same principle is to simply serialize your data when it changes. Here is a 6 method long solution. There are several frameworks available: SIXX saves objects in XML format, ReferenceStream (SmartRefStream) in Pharo, BOSS (Binary object storage system) in VisualWorks, and ObjectDumper in GNU Smalltalk allow one to serialize objects in a binary format. These frameworks support cyclic references.

To illustrate this simple method, we show how Conrad, the conference registration system for ESUG (http://www.squeaksource.com/Conrad), applies such an approach. The root of the model is CRConference. Whenever the application changes something in the model it calls CRConference>>snapshot which saves the complete model. At start up we make sure that the latest version is always loaded.

The method CRConference class>>load: loads a specific version. CRConference class>>initialize and CRConference class>>startup make sure that always the latest version is loaded.

Since Conrad only manages one conference, it uses an singleton that can be accessed using the message default and reset using the message reset.

CRConference class>>default
^ Default ifNil: [ Default := self new ]
CRConference class>>reset
Default := nil
CRConference class>>load: aString
| stream |
stream := ReferenceStream fileNamed: aString.
[ Default := stream next ] ensure: [ stream close ]

Afterwards we make sure that at image start up, the latest version is loaded. To do so, we specialize the class method startUp which is invoked when the image is starting up.

CRConference class>>startUp
| files |
self reset.
files := FileDirectory default fileNamesMatching: '*.obj'.
files isEmpty ifFalse: [ self load: files asSortedCollection last ]
CRConference class>>initialize
Smalltalk addToStartUpList: self

Now we save the data, by creating a reference stream in which we add date and time information for tracing purposes.

CRConference>>snapshot
| stream |
stream := ReferenceStream fileNamed: (String streamContents: [ :filename |
Date current
printOn: filename
format: #( 3 2 1 $- 1 1 2).
filename space; nextPutAll: (Time current print24
collect: [ :char | char = $: ifTrue: [ $- ] ifFalse: [ char ] ]).
filename nextPutAll: '.obj' ]).
[ stream nextPut: self ] ensure: [ stream close ]

We illustrated the principles using ReferenceStream but it would be the same with another object serializer.

Again with 6 methods you get a working and robust solution that has some limits: first this is the responsibility of the developer to track when to save the objects, second, saving all the data each time one single element changes is not optimal and works for small models. Third with large data, saving subpart can be tedious because you may reload parts and you may have to swap the one in the image with the one loaded.

Copyright © 19 March 2024 Stéphane Ducasse, Lukas Renggli, C. David Shaffer, Rick Zaccone
This book is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 license.

This book is published using Seaside, Magritte and the Pier book publishing engine.