> As a newbie in Magritte, I don't understand well how the new widgets
> work in Pier. For my personal web site I'm programming in Pier, I
> created a PRBoxWidget instance to encapsulate other widgets.
widgets are essentially just Seaside components, but instead of
#renderContentOn: you override #renderWidgetOn:. They also provide a
settings command so that administrators can configure them from the
web. It is also possible to plug in any Seaside component, e.g. the
Sushi Store, but these are not configurable from the web.
> In my case, I like to have two instances of my site main class in
> my disptacher:
> one for admin displaying everything and one for everybody with only a
> PRSearchWidget and a PRTree (no commands, no views); each one pointing
> to the same kernel. So until you don't know the url to access to the
> admin path you don't see the 'login' link.
> I did this using:
> PRBoxWidget subclass: #MyNavigationWidget
> instanceVariableNames: 'adminPool userPool' ...etc
> self adminConfigFlag ifTrue:
> [adminPool do: [:ea | html render: ea] separatedBy: [html
> with adminConfigFlag being a simple boolean in the associated
> super initialize.
> adminPool := Array with: PRTreeWidget new with: PRCommandsWidget
> new with: PRViewsWidget.
> userPool := Array with: PRTreeWidget new with: PRSearchWidget
> Not a beautiful OO way to do things but it worked. But now I am a bit
> lost. If you understand what I mean (and you have time), I'll be glad
> you shortly explain where to look for to change this in the new way
> because now it doesn't work.
The new way? I guess I didn't change anything special there, just the
way components get initialized using Magritte? If this breaks
something this was not intentional. Maybe you need to reset the
settings of the widgets.
> It's maybe a easy task to do but I don't know how to rethink my
Did my latest changes break something in particular? Do you have a
stack trace? What is the particular problem?
> PS: great change in visitParagraph: . It's cool. I did those kinds of
> modification in order to avoid a <div class='paragraph'> in the
> start of
> the default page (as I need to manage two absolute divs). Your way
> is better.
Thanks. I wanted to blog about that. This is absolutely needed to
create sophisticated CSS layouts ...
I would like to ask a question to the Pier users before doing a
change to the Pier widgets: Currently every widget has its own
hardcoded <div class="[custom_classes]" id="[custom_id]"> around
itself and it also emits a <h1>. I am currently building some new
sites and these <div> and <h1> tags rather hurt than help.
I wonder if we shouldn't get rid of those <div> and <h1> altogether?
I guess this is sort of a relict from SmallWiki where there were no
environments. Nowadays designers can add <div> (or other tags) around
a widget within the environment if necessary. There is no need to
write Smalltalk for that anymore.
Does that make sense?
I am creating a model class that only has a few core attributes and
will allow the user to create descriptions through a description
editor. Is subclassing MAAdaptiveModel a smart alternative to using
customDescription on the class side (as seen in Exercise 18 in
I want to let users click on a URL, like
where viewing do_something needs a login and a parameter. If they are
not logged in yet, I want them to login, using the PULogin command,
and then do_something should be executed (without needing another
What I do now is:
By changing the start: method I can let the command (my own PRCommand
subclass DoSomethingCommand) capture the parameter param1 in an
instance variable. I know that I can check context isLoggedIn inside
DoSomethingCommand>>doValidate. But how do I transfer control to the
PULogin command to give the user a login page, and then get back to do
the rest of the validation for my command?
Any pointers will be greatly appreciated :-)
Magma provides a virtually transparent persistency mechanism, in which
the application, in this case Pier, need hardly be aware of the fact
that not all of the objects which it uses are kept in memory all of the
time. As far as Pier is concerned Magma will stub out objects in memory,
and load them in, a process termed reifying, or reification, as needed,
Pier provides very controlled access to its model, including awareness
of persistency issues, so it makes sense to make use of this in the
However, Pier will have to curb its tendency to traverse its entire
model for some of its operations (e.g. page removal) in order to play
sensibly and scalably in a Pier-Magma installation.
The Database Structure
The root of the Magma database is an instance of PRMagmaRepository. This
is a minimal root object designed with the intention of being able to
merge with root objects from other projects. For example GJallar will
have a root object of its own. To adopt or merge with Pier's
requirements, all that is needed is for their root object to have an
accessor #pier, onto a standard Dictionary.
PRMagmaRepository is a subclass of PRObject, and so has properties by
default, if you can think of a reason or need to use them they are there
but they are not currently used.
When running Seaside-Magma-Pier, the aforementioned Dictionary in the
root of the database is directly available from the Seaside session via
the convenience method #pierPersistencies. (in the latest version,
previously it was just #pier)
"session pierPersistencies", yields a dictionary of, PRMagmaPersistency
instances, keyed by PRKernel name, so to obtain the PRKernel instance of
(session pierPersistencies at: 'MyPier') kernel
This does the job fairly logically.
ReadStrategies in Magma-Seaside
The root object of the repository also provides the Magma read strategy
for the repository via #buildReadStrategyOn: . A ReadStrategy tells
Magma how many objects to load in simultaneously.
For example, in Pier we tell Magma to reify all of the objects in a
PRDocument structure in one database access/hit, since we will need them
all to display or process the page. For more details about the Pier
read strategy see below.
This functionality, whereby the root object supplies the database
read-strategy, is provided in WAReadStrategyDefault as a standard way of
providing a read strategy for seaside applications in the package
There is an alternative WAMagmaReadStrategyWithLogging which provides
some logging features, and this can be selected in the application
configuration by over-riding the 'read strategy' setting. Logging is
invaluable in fine-tuning Magma read strategies.
Magma and Seaside Sessions
Since Pier manages its own model locking, it is perfectly ok to share a
single Magma session between all seaside sessions. This functionality is
provided by WAMagmaSharedSession.
Other Seaside applications (Gjallar again!) have more complex
arrangements using session-pools, but the basic WAMagmaSharedSession
provided in the Magma-Seaside package is fine for Pier.
When running using WAMagmaSharedSession a single Magma session is opened
for each application (#obtainMagmaSession), and is available from the
seaside session via #magmaSession. The root of the database from the
magmaSession obtained via #root.
The Pier-Magma package defines the convenience method #pierPersistencies
as already mentioned.
The model locking performed by Pier is handled by the persistency
scheme, PRPersistency and its subclasses. The default #execute: method is:
self mutex critical: [ self apply: aCommand ].
The change required to support Magma is minimal:
self mutex critical: [ self session commit: [ self apply: aCommand ] ]
What is In memory vs What is in the DB
When using PRMagmaPersistency, the master list of PRKernel instances,
kept in PRKernel-instances, contains a 'stub'. This is an instance of
PRKernel, having #persistency as an instance of PRMagmaPersistency (also
a stub), but no data, i.e. #root is nil.
Whenever Pier wishes to obtain the real object, which is in the
database, it calls, #realize on the stub, which calls #realizeKernel on
its (stub) PRMagmaPersistency, returning the real PRKernel object, with
a non-nil root, from the database. The real PRKernel object, also has a
real #persistency, which is what is used to perform commands and logging
[The model locking mutex which is used at present is the one in the
persisted PRMagmaPersistency, if this causes problems, then it will be
possible to use the mutex in the memory resident (stub)
Behind The Scenes - Saving The Model
Before persisting some objects, Magma calls #maPreserialize.
[ I am warned that this approach may be deprecated in the future! -- kph ].
This is used:
1) to remove the mutex from PRPersistency
(Disabled at present. The mutex used to be in PRKernel and was lazily
initialized, so removing it before persisting was fine, it would just be
reinstated when next used.
If it becomes necessary to re-enable this, then we will have to see
about asking Lukas to lazily initialize the mutex once more)
2) To remove any decorations of PRChildren if they are empty. The
current model implementation should not be creating empty PRChildren
decorations anyway, but this is just in case.
3) Context's are tidied up before they are persisted. Properties are
removed, and commands are copied, and command's answers are copied. This
is to support logging.
Behind the scenes - loading the model
This is the read strategy that Magma-Pier uses at present:
strategy minimumDepth: 0;
"forVariableNamed: 'pier' onAny: PRMagmaRepository readToDepth: 2 ;"
forVariableNamed: 'kernel' onAny: PRPersistency readToDepth: 1;
onAny: PRKernel readToDepth: 1 ;
forVariableNamed: 'decorations' onAny: PRDecorated readToDepth: 1;
forVariableNamed: 'title' onAny: PRStructure readToDepth: 1;
forVariableNamed: 'children' onAny: PRChildren readToDepth:
(self readPathSkeletonInOneHit ifTrue: [ 1 ] ifFalse: [ 0 ]);
onAny: PRDocumentItem readToDepth: 1; "reads all page items in
onAny: PRComponent readToDepth: 1;
If the flag #readPathSkeletonInOneHit is set, Magma, realizes all of the
tree of objects necessary to resolve a url-path, in one database access
cycle/hit. Depending upon other settings, this data may remain in
memory. Otherwise, resolving a url-path occurs one level at a time.
As you would expect the items required to display a page, are loaded in
The ideal situation would be to have a path lookup cache which can
perform the path look-up in one hit, and possibly obtain the whole page
data in the same hit. This should be relatively straight forward, using
an indexed MagmaCollection.
The logging implementation used in PRImagePersistency has changed since
the Pier-Magma integration was written, and so it follows the previous
It stores a snapshot of the original data-structure, together with a
collection of the context/commands that are applied to it.
(it probably isnt working as intended at the moment, review required)
feedback comments to keith_hodges(a)yahoo.co.uk
The Second Chapter
Configuring Pier to work with Magma
Step 1. Add WAMagmaConfiguration to your pier app
- In /seaside/config application, click on the 'configure' link next
to your pier application.
- From the drop down menu named 'Add Ancestor', select
'WAMagmaConfiguration' and click the 'Add' button.
- (optional step) to be tidy, click the '(remove)' link next to
'WARenderLoopConfiguration', since WAMagmaConfiguration includes this
Step 2. Set the session class to 'WAMagmaSharedSession'
- In the general config section, in the line entitled 'Session
Class' click the 'overide' link.
- From the drop down menu which appears next to 'Session Class'
Step 3. (optionally) Set the location of the magma repository.
- The default is set to use a directory named 'magma' in the image
- overriding this setting to choose an alternative directory, or a
remote magma server.
Step 4. Save Changes and Close.
- click the 'Save' button at the bottom of the configuration page.
- click the 'Close' button to return to the dispatcher editor.
Notice the appearance of a link next to the 'pier' application, 'magma'!
Step 5. Create the magma repository for pier.
Enter the control panel for magma using the 'magma' link next to your
The top panel should report an error, (i.e. there is no database yet)
* Repository path setting: *magma
* Error: /media/hda1/squeak/pr_gsoc/magma/objects not found.*
At present this magma control panel is application agnostic, it doesnt
know anything about pier, hence you have to explicitly choose what class
of root object the database should be created with. (Some magma-seaside
users e.g. Gjallar, just have the app initialize the database
automatically when it is not found)
- To create a repository for pier in the directory specified, choose the
class of the desired repository, in this case a 'PRMagmaRepository',
click the 'create' button.
On returning you will see something like this.
*Repository Path Setting: *magma (delete)
*Persisted Objects Count: *569
*Session Id: *2
*Cached Object Count: *670
*ReadStrategy: *a WAMagmaReadStrategyDefault
*Root Object: *a PRMagmaRepository (explore)
The 'delete' link will delete the repository and start again.
The 'explore' link, is similar to the seaside 'debug' link, it opens an
explorer in squeak on the root db object.
Returning to the seaside/config app, click the 'pier' link to obtain the
pier persistency manager. There you will find a ui for changing which
kernel is served* and its persistency scheme.
*the 'serve all kernels' option needs the class PRMainAllKernels which
is not loaded
Switching from PRNullPersistency to PRMagmaPersistency is all that is
Then click the 'migrate' button, and later 'commit' the change.
I've played with pier using the image from  mentioned today in .
This does contain magritte, pier and magma. It seems Pier does not use
magma by default. Is there some description of how to make pier use
magma for persistence?
My error was in attempting to run pier with magritte still 30 versions
Now that I have tested it with an up-to-date magritte, the
seaside-magma-pier instructions that I have previously posted to the
smallwiki mailing list should now work.
1) Load seaside and pier as usual,
update to at least Seaside 2.7a1-kph.214 because that has a small fix in
2) Load the latest Magma from squeaksource project, MagmaTester, package
3) Load Pier-Magma, and Pier-PersistencyManager packages
Everything has a UI from there. Configure your app to have
WAMagmaConfiguration, and WAMagmaSharedSession. Use the 'magma'
dispatcher editor plugin link to initialize the database, and the 'pier'
dispatcher editor plugin link to switch your pier kernel between
persistency schemes. (i.e. to turn PRMagmaPersistency on/off).
I am sending detailed instructions to the list for building and
configuring a seaside magma pier image. There is just one slight snag, I
haven't got it working with the latest pier yet. When I do I will also
provide a preloaded image.
The first chapter!
Preparing a Seaside-Magma-Pier image from scratch. Their follows an
Installer script that you can use to build an image or compare with your
current image to see if it contains the required components.
(this should potentially work in 3.7, 3.8, 3.9, 3.9 KernelImage or 3.10):
Obtain latest Installer-Core from http://www.squeaksource.com/Installer
"Image building script (execute in a workspace):"
squeakmap := Installer websqueakmap.
squeaksource := Installer squeaksource.
lukas := Installer repository: 'http://mc.lukas-renggli.ch/'.
"install some pre-requisites"
squeakmap install: 'DynamicBindings'.
squeakmap install: 'KomServices'.
squeakmap install: 'KomHttpServer'.
xmlparser := squeaksource project: 'XMLSupport'.
xmlparser install: 'XML-Parser-mir.9'.
seaside := squeaksource project: 'Seaside'.
seaside answer: '*administrator*' with: 'seaside';
answer: '*config*' with: 'seaside';
answer: '*password*' with: 'admin'.
"install latest seaside and scriptaculous"
seaside install: 'Seaside2.7a1-kph.214';
"install latest magma"
magma := squeaksource project: 'MagmaTester'.
magma install: 'MagmaServerLoader';
install: 'Magma seaside';
install: 'Magma sunit'.
magma install: 'Seaside-Examples-Store-Magma'.
"install latest magritte and pier"
lukas answer: 'Would you like*' with: true;
answer: '*name of your Pier kernel*' with: 'Pier 1.0.5 SMP';
answer: '*entry point*' with: 'pier';
answer: '*pplication*' with: true.
lukas project: 'magritte';
lukas project: 'pier';
"lukas install: 'Pier-Security'. "
I noticed that newer Pier and Magritte-Seaside commits in MC have a few
comments about being "for very latest Seaside." I assume that this means
Seaside 2.8. First, it would be nice if the exact version was stated in
the comments so we could tell what "very latest" means :-). Second: are
these _only_ for Seaside 2.8, or will they work in 2.7? If not, it would
be best if these could be labeled to reflect their exclusivity.
( I didn't see that this has been discussed before.)
+1 (408) 799-6124