[TransWarp] Binding templates and resources

Phillip J. Eby pje at telecommunity.com
Tue Jul 29 22:41:39 EDT 2003

At 07:02 PM 7/29/03 -0400, Phillip J. Eby wrote:
>Resources must be referenceable in application URLs.  So we're going to 
>have to reserve a URL name (tentatively '++resources++') to get at 
>them.  A resource will be accessed via 
>'/++resources++/some.package/resourceName'.  There will probably be a 
>configuration property or properties to control this.

This is slightly more complex than it first appeared.  For one thing, we 
don't want to allow traversing to arbitrary package names, if this results 
in module imports.  That's a security problem, since it opens up anything 
on PYTHONPATH to execution.  So it's going to be necessary to declare 
specific properties to enable access to package resources.  :(

It also has occurred to me that there may be circumstances where a package 
needs to assert other global items than "resources".  And, our proposed 
mechanism hasn't been thought through for non-filesystem resources, e.g. 
skins stored in a database.  Also, as I've been trying to move to more 
detailed design, I've been frustrated by the practical difficulties of 
layering heterogeneous location types - i.e., layering a skin-style 
organization atop the "included-in-the-package" style.

Part of the problem is that the desired namespace mixes a number of 
"co-ordinates": skin, package, and resource/template name.  Skins need to 
be composable from multiple layers, and property definitions aren't well 
suited to this.

Perhaps if I created a "multiPropertyMap" type that aggregated multiple 
PropertyMaps, I could address that.  Perhaps specifically what I should do 
is create a Skin class that did such aggregation by delegating 
configuration lookups to a sequence of "layers".  Downside: layer instances 
wouldn't be sharable, since they'd effectively be doing 
caching.  Ick.  Maybe we need to drop the idea of caching at the property 

If there's an explicit Skin object, though -- even for "unskinned" 
applications -- we can leave the caching to it.  This simplifies 
configuration to a large extent, since we don't need to account for caching 
in every property definition.  Now, any "special" handling (e.g. loading 
resources from a DB) can be delegated to a "layer" component, which need 
only offer properties, in order to override an individual resource or template.

The only caveat here that I see is that resource/template loaders may need 
to be careful how they set parent components for the objects they create, 
or else bindResource/bindTemplate will need to explicitly delegate lookups 
to the skin.  That isn't a bad idea in principle, since it's quickly 
accessible as 'interaction.skin'.  In practice, alas, the 'bind*' 
operations don't necessarily have access to the current interaction, 
without doing a utility lookup that would hit the skin first anyway!  Ugh.

But, I think the benefits of having Skin.getResource() and 
Skin.getTemplate() methods would be very, very nice.  First, we encapsulate 
the lookups behind an interface that can be independently re-implemented, 
without forcing the specific mechanism on everybody.  Second, the default 
Skin implementation can delegate to Layers, with a default Layer to 
implement the package-based rules, and it can cache the return values -- or 
not.  (A DB-backed skin processor implementing a large-scale 
private-labelling scheme may need to cache things differently than a small 
set of filesystem skins.)

Downsides: pushing caching into the skin means that the lower-level 
components can't update a resource's "freshness".  (OTOH, the Skin could 
perhaps adapt resources to a "caching-hints" interface, and we could add 
that later.)

So far, discussing "resources and templates" is also rather tedious; it may 
be that we should talk about "static and dynamic" resources, or maybe even 
"data and code" (data and executable?) resources.  The difference in each 
case is that the first kind of thing (resource, static resource, data 
resource) is effectively a singleton - it has a unique URL (or at least 
path from the application root).  Some examples of these "data resources" 
include images, help pages or online manuals, Java applets, JavaScript 
files, etc.

The second kind of thing (template, code resource, dynamic resource) is 
method-like, in that it doesn't have a unique URL, and it can be accessed 
only via objects that bind it.  Currently, the only such things we have are 
PWT templates, and I don't currently have anything else in mind to build, 
but I dislike locking Skin into this with a 'getTemplate()' method.

Anyway, having a 'web.IResourceManager' interface for Skin to implement is 
probably a really good idea.  It should also make it easy to hook up the 
/++resource++ namespace, by relatively simple delegation to the skin.

Still left open, is the question of URL management for data resources.  In 
part, this is because absolute URL management in general is still open.

Probably, ITraversable needs a 'getAbsoluteURL(interaction)' method.  Skins 
and data resources should be ITraversables themselves.  The default 
implementation of getAbsoluteURL() would be to get the parent traversable's 
absolute URL and concatenate the local traversable's name.  (If the name is 
None, this indicates that traversal is at the root, so the interaction 
should be asked for a base URL.)  Data resource's parents would be the 
directory, package, and skin components that live above them, with the skin 
supplying a base absolute URL based on /++resource++.

This will deal with all our absolute URL needs for singletons such as data 
resources and application service objects (e.g. Specialists).  For 
individual model.Element objects, we'll need to be able to find their 
specialists, which is still an open issue, but at least we can define the 
interface now.

It appears that Skins will work by way of path traversals as well, with the 
getXResource() methods simply translating to path traversals based on the 
input parameters, with caching of fully-traversed paths.  It looks, too, 
like we'll finally need that multi-traversing decorator that simultaneously 
traverses more than one path.

This concludes another rambling PEAK design stream-of-consciousness.  :)

More information about the PEAK mailing list