From: Loren Stafford [mailto:lstaffor@dynalogic.com]
Now that I've had breakfast and thought about this a little more, I see there is broader issue: how to handle the special needs of objects that are private to a product. My product is an event scheduler. (Terry, who started the "object icons" thread, may have a different situation. Jump in and tell us about your product, Terry.) The Scheduler product registers an catalog-aware Event class so user's can define scheduled events. The product keeps track of all Events in a ZCatalog "Schedule". Now, Schedule is a persistent object and has a class definition, but the one and only instance is created by the product and load time, if an instance doesn't already exist. The Schedule has some special usage requirements:
1. There should be only one instance. That's why its class is not registered.
Hmm, I guess I don't see the necessity of making it a Singleton here. Suppose you need to segregate events into separate priority classes, or guarantee that, when executed, the run with the permissions of different users? Splitting up the schedule _might_ not be a terrible thing to do. Your default case could then just require dropping a single instance of the Schedule class at the root of your Zope hierarchy, and leaving it there.
I'm beginning to think that way too. I haven't really dealt with priority or permissions yet (and I probably won't until Phase II), but trying to enforce a singleton is more trouble than it's worth.
What are your problems? Doesn't my code work anymore? The reasons I chose to make ZScheduler a singleton are: 1. Extra threads in Zope affect the performance of Zope. Only one ZScheduler object needs only one extra thread. 2. Event objects should be able to find the ZScheduler at all times, just like the Add list can count on the id Control_Panel existing. 3. The ZScheduler object can act as a management interface into the underlying Events, like show what events are about to be executed, show reports on the number of Events executed, etc. Priority could simply be a property on a Event object, something that can then be sorted on from the catalog. No multiple Schedulers needed here.
2. It probably shouldn't show up on users' navigation
bars and folder lists.
This probably is not a problem, because Schedule has a unique meta-type. But that's not a watertight solution. A standard method for marking it invisible would be better.
If Schedule derives from ZCatalog, as it seems, and the Event class uses the well-known schedule ID as its default_catalog_id, then it isn't even necessary to "contain" the events within the schedule object -- they will find it anywhere above them in the tree by acquisition (think "uncle Schedule" instead of "papa Schedule").
I guess I envisioned a single Schedule, because I imagined only a single Dispatcher thread. If there are more Schedules, either the Dispatcher will need a catalog to find all of the Schedules, or each Schedule will need it's own dispatcher. Let me hold that last thought for awhile...
Again, there is no need to have more than one Scheduler, you solve no problems with that, you only create more. You don't need to hide the ZScheduler from view, just like you don't need to hide the Catalog. It can be used as a organising container for everything related to Events as well. Stock Catalog objects are containers for the same reasons.
3. If and when it does show up (as on the manage_main
menu) it should be
identified with the product (to avoid the "Whaz dis?" confusion). That's why I want it to have an icon that shows it is part Scheduler product.
Solved if Schedule is an "ordinary" ZClass. Check.
Solved if you cannot manually add new Scheduler objects. KISS, keep it simple, stupid.
4. No one, not even a manager, should be able to delete
it accidently. You
can make an object undeletable by putting its ID in the list of reserved names, but I have found, during development of Scheduler, that this hack causes more problems than it's worth. I might settle for letting be deleted by a manager.
Again, solved for "ordinary" ZClass instances -- just set the permissions so.
I sort of agree. One problem with deleting a Schedule is if it has events cataloged in it -- currently that breaks the event objects. A manage_beforeDelete method could just block a delete in that case. Also the Dispatcher task has to be terminated. There must be a way to do that in a manage_beforeDelete method.
Martijn what do you think? You clearly went to a lot of trouble to put the Product in control of deleting the Schedule catalog.
What are the problems you are experiencing? Especially for the development and alpha/beta stages of the ZScheduler product, I put a hook onto the ZScheduler Product folder to release the protection on the root ZScheduler object when you delete the Products folder. Yes, it is a hack, but it worked for me. I planned on removing it when releasing a stable version. For the reasons I went through all the trouble (which wasn't all that much of a trouble, really. Zope provided the framework), I named earlier in this email.
5. When the product is deleted (I mean really deleted,
because you don't
want to use it anymore), the Schedule should be deleted too. Failing this, it should at least be deletable (an iffy situation, if you use the reserved_names hack). On the other hand, if you are just updating the product code, you probably don't want to delete the Schedule object. It may contain scheduled events. This is complicated by the fact that when you load a product, Zope first deletes the old product. So a manage_beforeDelete method can't distinguish between a "real" delete and a code update. I've also discovered that any error in a product's manage_beforeDelete method makes the product not only undeletable, but (because of the implicit delete) unupdatable (un-update-able)!
(Hmmm. There's an idea. You could make any object, including the Schedule, undeletable by giving it a manage_beforeDelete method that raises an error.)
Indeed, don't delete the ZScheduler automatically. Just state in the documentation that this is unstable, development-grade software, and document the procedure. A product update then will cause the lock to be removed, and then reinstated. If you run into problems with the code, you can use the Monitor to release the lock manually.
6. The Schedule need to have a "well known" ID (I think). This is for use in the default_catalog property of the events. I wouldn't want someone to change the ID of the Schedule arbitrarily. This may be the same problem as accidental deletion.
You can override the setId() method to prefent changing the id; BasicUserFolder does this::
def _setId(self, id): if id != self.id: raise Globals.MessageDialog( title='Invalid Id', message='Cannot change the id of a UserFolder', action ='./manage_main',)
Thanks. I'll use that.
Doesn't using the proetction I implemented also protect you from changing the id? It should! You can't change the id of the standard_html_header/_footer and Control_Panel either, can you? Anyway, since I sort of dumped the code on you, please feel free to ask more questions =) -- Martijn Pieters, Software Engineer | Digital Creations http://www.digicool.com | Creators of Zope http://www.zope.org | mailto:mj@digicool.com ICQ: 4532236 | PGP: http://wwwkeys.nl.pgp.net:11371/pks/lookup?op=get&search=0xA8A32149 -------------------------------------------