watch this The wheels are turning, slowly turning. home
Axiom Powerups 2005-11-17



Q: When I run axiomatic -d my.axiom start, a web server starts up. How does that work?



A: The web server is started and stopped by an instance of an Axiom Item subclass, xmantissa.website.WebSite. WebSite powers up the database into which it is installed. Power up is the term used for a particular manner in which one Item can be used to enhance the behavior of another Item. It means that WebSite is calling powerUp on the site store1, passing itself as the powerup Item and twisted.application.service.IService as the interface. The start subcommand of axiomatic kicks off the standard Twisted service startup events: an Axiom database behaves as an twisted.application.service.IServiceCollection, with each IService powerup treated as a child. In this way, things like WebSite are given startup notification (as well as shutdown notification, when the database is about to be closed).





Q:Wait, what? You make no sense.



A: Okay then, here’s some example code, perhaps it will make more sense:

from zope.interface import Interface, Attribute
from axiom import store, item, attributes

class IEngineEnhancement(Interface):
    "An improvement to a ship's engine."
    speed = Attribute("How much faster this makes a ship go")

class IShieldEnhancement(Interface):
    "An improvement to a ship's shields."
    force = Attribute("How much stronger this makes a ship")

class Spaceship(item.Item):
    typeName = 'spaceship'
    schemaVersion = 1

    score = attributes.integer(default=0, doc="how well the player is going")

    def getMaxSpeed(self):
        return sum(enginePowerup.speed for enginePowerup in self.powerupsFor(IEngineEnhancement))

    def getMaxShields(self):
        return sum(shieldPowerup.force for shieldPowerup in self.powerupsFor(IShieldEnhancement))

class HyperDrive(item.Item):
    typeName = 'hyperdrive'
    schemaVersion = 1

    speed = attributes.integer(default=100)

    # Here is the powering up part
    def installOn(self, ship):
        ship.powerUp(self, IEngineEnhancement)

class SuperShield(item.Item):
    typeName = 'supershield'
    schemaVersion = 1

    force = attributes.integer(default=50)

    # And here is a little more.
    def installOn(self, ship):
        ship.powerUp(self, IShieldEnhancement)

def main():
    st = store.Store()
    ship = Spaceship(store=st)
    driveUp = HyperDrive(store=st, speed=35)
    shieldUp = SuperShield(store=st, force=1000)
    extraDriveUp = HyperDrive(store=st, speed=20)

    for powerUp in driveUp, shieldUp, extraDriveUp:
        powerUp.installOn(ship)

    print "Your ship's maximum speed is %d." % (ship.getMaxSpeed(),)
    print "It has a maximum shield level of %d." % (ship.getMaxShields(),)

if __name__ == '__main__':
    main()






Q: Hey! Isn’t this just a bridge table with a funky API?



A: Yes. Yes it is. We find the pattern so useful, we added special support for it.






1
Site Store is the name of the Axiom Store which is at the “top” of everything: it is the database in the directory you pass to “axiomatic -d”, it contains login data and other site-wide state. It is conceptually distinct from user stores and application stores and serves a different purpose from each of them.