[Zope-PTK] ZPatterns and DatabaseAPI (was Getting it allto
Phillip J. Eby
Wed, 05 Jul 2000 19:47:00 -0500
At 05:23 PM 7/5/00 -0400, Shane Hathaway wrote:
>> Actually, you released first, as I recall, because I downloaded DatabaseAPI
>> in the hopes that you had already done what I needed for the database parts
>> of ZPatterns. Unfortunately, I had the same problem with your product as
>> others have with mine - i.e., lack of good conceptual and practical
>> introductions to it.
>Perhaps. It did come with a demo.
I think I might have looked at a *much* earlier version than the one that's
now available. In any case, I understood it this time around. :) I
didn't look at the demo, though, just installed it and played with it.
>I have been trying to deconstruct the ideas that I came up with in
>developing DatabaseAPI and ACLManager. Development of the following
>would make DatabaseAPI irrelevant (a strange goal, I know, but the idea
>is to make Zope more integrated, not less):
>1. An object type called "Interface method", which would be addable to
>ZClass definitions. Thus we could write ZClass-based interfaces.
>2. A change in the ZClass UI that would make it easy to write method
>implementations. The developer would just subclass the interface and
>instantly know what methods need to be implemented. Note that
>interfaces could be written in filesystem-based Python also.
>3. Standardization in method invocation semantics. I struggled a lot
>with the fact that DTML Methods are invoked one way while Python
>Methods another. I found a way to force DTML methods into obedience.
Yes, those all sound like very useful things to have. I'm not sure that
Jim would be happy with the idea of subclassing from an interface, but he
would probably like the idea of being able to declare that a ZClass
*implements* an interface.
>2. Rule-based local roles, which may take the form of "groups".
>ACLManager could do something like this, but the idea that was brought
>out today would be much more integrated.
>3. Integrate the code for persistent cookies into LoginManager. It
>would be some form of a plug-in. My code was able to share cookies
>between distributed servers and restore sessions when Zope is
It should be straightforward to implement as a LoginMethod, I would think.
Currently there is only a BasicCookieLoginMethod (user/pw encoded in
cookie) login, but the logic would be similar, differing only in what the
cookie is set to and what it's checked against. Subclassing
BasicCookieLoginMethod would be a good place to start.
>> >DatabaseAPI does not make any assumptions about the structure of the
>> >data, while ZPatterns assumes the data is stored in indexed database
>> That's not correct, actually. Each attribute or propertysheet of a
>> DataSkin may be "stored" anywhere, including "virtually" (i.e. computed).
>> One could implement a Provider/Trigger pair that made attributes that were
>> "stored" in X10 such that a Lamp object could tell you its dimming setting,
>> or change it, by manipulating that attribute (which would cause X10
>> commands to be sent to query or change the real lamp's dimming status).
>> The Lamp object would simply need some attribute to tell the Provider
>> and/or Trigger what the house code and unit code of the X10 lamp unit was.
>> Note that this attribute wouldn't even need to be the object's 'id'
>> attribute; it could be an attribute stored in the ZODB or in an SQL
>> database, or computed from some other attribute, which in turn could be
>> stored or computed in an arbitrary way, and so on.
>Okay, you're probably right, but the way one would approach this is
>entirely unclear. Let's make this a multiple-choice quiz. :-)
>To implement this scenario, you should start by creating:
>A. An X10AttributeProvider.
>B. An X10Specialist.
>C. An X10SheetProvider.
>D. An X10DataSkin.
>E. An X10Trigger.
>F. Other (specify)
If it were me, I'd probably make DataSkin-subclassed ZClasses like Lamp,
Appliance, and so on. These might usefully subclass from an X10Device
ZClass with a propertysheet for house code, unit code, and unit type -- if
I knew in advance I was making an X10 application, that is. (Note that one
of ZPatterns' strengths is in layering frameworks: I could take existing
Lamp and Appliance objects without any X10 knowledge, and still make this
work as long as they were DataSkins.) Then, I would either create folders
for my rooms, or create a Room ZClass based on ObjectManager, depending on
whether I wanted to do something like tell a Room to turn off all its lights.
I would place all this under a "Folder w/Customization Support", in which I
would include two Customizer objects, configured for Lamp and Appliance
respectively. Each would include an AttributeProvider and a Trigger. I'd
probably use Generic ones (which can call arbitrary DTML expressions). The
AttributeProvider and Trigger for Lamp would support a dimmingLevel
attribute, while the one for Appliance would support an "on" attribute.
They would do this by calling ExternalMethods (or perhaps a
DatabaseConnection's methods) to do the X10 work, passing in the values of
the house and unit code attributes.
At this point, I would be ready to add as many X10Device-based objects as I
wanted under my "Folder w/Customization Support". Any time I used
manage_changeProperties to change the dimmingLevel or "on" attributes of
these objects, the trigger would fire off a change to the X10 system at
transaction commit time. Whenever I displayed the object, the attribute
provider could fire off a query to the X10 system to find out its current
state. If I wanted to make methods on a Room to turn on or off all
appliances in that room (for example), I could just write a DTML method
that iterated over objectItems() of the appropriate type and called
manage_changeProperties on them.
>You will need to create a Specialist called House and put a Rack in
>it. You'll have to create an X10Device ZClass which is derived from
>DataSkin. The X10Device objects, which have the properties "title",
>"house_code", and "device_number", will be stored in the rack.
>B. Not quite (specify)
False. If you were going to create a Specialist in the scenario just
described, it would be "X10Devices", or "Lights", or "Appliances", not
"House". Specialists should be named as the plural form of an object's
role in the application. Which of these things you called your specialist
would depend on what your application needed. For example, suppose you
wanted your application to have the ability to globally report on X10
devices (e.g., show a list of used and unused house/unit codes, and what
objects are using them.) Then it would be meaningful to have an
"X10Devices" specialist. However, you would not put a Rack in this
specialist; it doesn't need one. Instead, you'd put a ZCatalog in it, and
then create methods in the specialist to use the catalog. Finally, you'd
go back and add new triggers to the Customizers so that when X10 devices
are added or deleted or have their house/unit codes changed, the trigger
updates the X10Devices specialist. (By the way, because ZCatalogs are
folderish, there's actually no need to use an actual ZPatterns Specialist
to implement X10Devices; an X10Devices ZCatalog would suffice and would
still allow you to add your reporting methods as subobjects of /X10Devices.)
Of course, it is also possible that you are using these X10Devices in
conjunction with a home inventory framework, which may include a Belongings
specialist. If it is ZCatalog based, you could use triggers to update it,
or you might add an additional Rack to it (which would be updated by
triggers from the original items).
Alternatively, the application *might* take the form of a database of
X10Devices rendered as a Specialist with a Rack, but it doesn't seem to me
to be suited to the needs of the application, which is probably overall
home management of some kind. It may also be that I have additional
control vectors besides X10, and I cannot use X10Device as a base class for
these things; instead, I may have to look up in another database, or have a
"controller data" propertysheet, that tells me the controller and its
parameters. Those controllers might all be DatabaseConnectors following a
common DatabaseAPI for light and appliance controllers.
Perhaps this example shows more clearly why ZPatterns is so "weird"
compared to the "normal" way of doing things. It's because it changes the
focus from "how" to "why", similar to the way the move from CGI scripts to
object publishing changes your focus from what operations the application
has to what operations each object class has. Instead of designing an
application around X10Device objects (ZPatterns says) you should focus on
creating a home automation framework. Then, use providers and triggers to
glue your abstract framework into a "real" implementation. This means, by
the way, that you can initially just use persistent attributes, and "test"
all of your home automation functionality (such as scheduling, macros,
etc.) without even having your X10 or other controller functionality
written yet. And your framework can be re-used by any number of developers
who can wire in whatever control mechanisms they want. (You could do this
with DatabaseAPI, but you would have a much harder time sharing your
objects with a seperately-written home inventory application that also
wants to deal with Rooms and such. And, your objects would have to have
explicit turnOn()/turnOff methods that delegated to the DatabaseConnector.
Which would mean that an integrator would have to merge your classes with
those of the other framework more directly.)
>To use a rack, objects must have an ID. A good choice of ID's might be
>the house code and device number concatenated together. Of course, if
>you have to change house codes because of a conflict with your
>neighbor, you have to change all the ID's.
<shudder> It's perfectly valid in X10 for more than one device to be keyed
with the same house and unit code, so it's a bad choice of primary key. It
would be better to give them meaningful ids.
>Then you'll have to write your own UI and storage mechanism so you can
>store and manipulate these things in the rack. This is what was
>required to use DatabaseAPI.
>B. Not quite (specify)
You'll need to have your objects be addable and editable through the
regular Zope methods, yes.
I think perhaps there was a miscommunication, however, as I brought up the
X10 object example as an application that you could do with ZPatterns, that
DatabaseAPI alone wouldn't be much help on. About all you could do with
DatabaseAPI in this situation is have it contain the API that talks to the
real-world X10 devices. It would have methods like turnOn(house,unit),
turnOff(house,unit) and dimTo(house,unit,level). These could be called by
ZPatterns triggers, or you could hardwire this into your X10Device class.
But without ZPatterns, you would not be able to:
* Have the on/off/dimlevel as standard Zope properties, and manipulate them
through standard interfaces (including WebDAV)
* Have the option of *not* storing the house/unit code information in the
object itself, but instead looking it up from some other source
* Catalog X10Devices in multiple catalogs, depending on their type and
* Have all of the above happen transparently, without problem-domain level
code having to "know" anything about how the X10 stuff is implemented.
This is why I say that ZPatterns and DatabaseAPI have very different -- but
sometimes complementary -- goals. I posted to Zope-dev yesterday a rather
in-depth analysis of the differences and similarities between DatabaseAPI
and ZPatterns, which you might find informative. I think there are API
aspects (and the private/public distinctions) which ZPatterns could
definitely make use of. However, if your goal of making DatabaseAPI
irrelevant by folding those capabilities into the Zope frameworks was
achieved, ZPatterns would pick them up for free or at a relatively low
cost. Those capabilities are mostly in the area of making interfaces more
rigorous, robust, and well-documented, however, rather than adding any
actual new capabilities. The goals of the ZPatterns framework itself,
however, would continue to require the existence of Specialist+Rack,
Folder+Customizer, and the assorted plugins that can be placed in them.