Forum OpenACS Improvement Proposals (TIPs): Alternative implementation proposal (implemented and ready to commit)

Having given a lot of thought to this, I realized that making packages fully-fledged types as proposed would be a considerable amount of work, particularly in regard to upgrade scripts.

Also, package semantics are such that it's not clear this is the best approach.

We already have "PROVIDES" and "REQUIRES" dependency information being kept for packages. Basing package extension by making packages true acs object types would not mesh cleanly with the existing dependency specifications.

In my implementation, I decided to implement package extension through the dependency information that's already available, by adding a new dependency type "EXTENDS".

This has the advantage of being very easy to implement, including upgrade scripts, plus it fits naturally into the dependency scheme for packages that already exists.

Also, unlike with acs object types, the implementation easily allows for "multiple extending" (package inheritance), which I've already found to be extremely useful to knit together two or more packages into a coherent whole.

I've also implemented a top-level (i.e. like "singleton-p") package attribute "inherit-templates-p", which implements the concept outlined in point #4 of Dave's original list.

So, for instance, to build subsites using the layout manager package recently committed to HEAD, you can write a package consisting of the following .info file snippet:

<provides name="layout-managed-subsite" ...>
<extends name="layout-manager" ...>
<extends name="layout-manager" ...>
<extends name="acs-subsite" ...>

and presto, off you go.

WHY DO WE WANT THIS:

It makes maintenance of custom versions of packages that make relatively minor changes or enhancements much easier. You don't have to modify the base package's source at all, and can easily update from the OpenACS.org CVS tree (of course, your package may not work correctly afterwards, which is true today for packages yours "requires"). It makes clear what's been customized because all of your customizations, including API enhancements, database extensions, as well as new or customized scripts can all be placed in a separate package.

This also greatly reduces the need to mount packages instances just so another package that requires it has a URL to reference for to serve pages from that package. A UI enhancement package like the ajax file storage package can simply extend its base package. Mounting the extended package essentially instantiates a file storage instance (sharing the extending package's package_id).

Since base packages share mount points and package_ids with the extending package, there's no need to mount or find the base package (file storage in the Ajax fs ui case).

PERFORMANCE IMPLICATIONS:

More directories need to be searched by the request processor when operating in normal mode. This adds a small amount of overhead to request processing time. On the other hand, implementing this required me to visit, understand, and finally substantially simplify, speed up, and rewrite that part of the request processor that finds an appropriate .vuh file to serve if an exact file match cannot be found.

In performance mode (the one that counts), URL-to-file mappings are cached anyway, so this minor performance hit only has to be paid for the first visit.

There's also a slight performance hit during restart, as the NSV array that contains the URL-to-file search order for each package_key is built during startup.

SIDE EFFECT:

The recursive set of "extends" and "requires" results in a DAG rooted in the current package when graphed such that each package only occurs once in the graph. The simple algorithm to build the URL search order from this abstract graph is very similar to that required correctly call APM callbacks when a package is mounted, etc. Indeed, if "inherit-templates-p" is true, the resulting ordered lists of packages are simply the reverse of each other.

This same recursive walk algorithm is used to compute the correct order of Tcl library sourcing for each package.

Currently during startup packages have their Tcl libraries sourced in ascending alphabetical order, which only works because packages rarely have dependencies on each other in their init files.

Future work, then, includes sourcing package Tcl libraries in correct order based on their "extends" and "requires" dependency hierarchies.

WHAT'S DONE:

1. new dependency type "extends"

2. migration of parameters to packages that extend others

3. package instantiation, mount, unmount etc with callbacks executed in the proper order.

4. APM UI changes to allow the specification, display and editing of the new attributes.

5. request processor changes

The semantics seem right to me, daveb has a copy of the code and will be reviewing soon. After review, I propose committing the code and making examples available, and updating documentation to reflect the new capabilitles.

Cool stuff, really looking for it! I think this will easy contribution and extensions as well while we maintain an stable code base.
I think other OCT would like to check the code as well (including me).