[Zope3-dev] [DRAFT] Uniform resource identifiers (cpsskins)

Jean-Marc Orliaguet jmo at ita.chalmers.se
Mon Mar 27 17:17:43 EST 2006



Hi!

I've began formalizing some ideas about how to identify application 
resources:
http://svn.z3lab.org/trac/z3lab/file/cpsskins/branches/jmo-perspectives/io/README.txt

I post to zope3-dev too in case someone has some ideas about it. A lot 
of the points described are pertinent to zope3.

The background is the following:

Being able to identify application resources is important. First we want 
to identify what *type* of resource we have (a portlet, a widget, a 
style, ..) then we want to identify the resource itself in the context 
of the application, for instance if a portlet named '12345' is a unique 
instance of an object, a slot named '12345' will refer to a collection 
of objects, not to an individual instance.

So to start with the resource's own identifier:
The object's id in a container is not necessarily the id that is 
interesting (for instance if an item gets moved from a folder to another 
folder there can be id conflicts even though being located in a folder 
is nothing special for a resource, it might be an accidental thing).

In cpsskins the resource's id is the name of the resource in the 
*context of a relation*.  Hence resources are IRelatable:

    unicode(IRelatable(resource))

returns the resource's name in a relation. It is the only identifier 
that is used throughout the application to refer to the resource, ie. to 
register the resource, to customize it, to set it in relation with 
another resource, etc.

Note that in the case of containment  there are implicit container <-> 
parent container relations, so that item ids are also defined in the 
context of a relation it is just that these ids are only unique inside a 
same container.

Then we have the resource's type(s). Zope3 uses dotted names (e.g. 
widget.textinput) as well as interfaces (e.g. 
zope.form.widgets.interfaces.ITextInput) to identify object types. Both 
approaches provide a way of having unique identifiers mostly by creating 
namespaces.

The issue with dotted names is that there are no explicit rules for 
creating the names between the dots. Enforcing a policy can be difficult 
especially across different applications. The categorizations may change 
and renaming resources is not trivial. However dotted names are easy to 
transport (they are URL-friendly, they can be embedded in any export 
format XML, json, ...).

The issue with interfaces used as identifiers is that packages are often 
reoganized and the resources often change name. The coupling is very 
tight between the application's package organization on the filesystem 
and the way the data is described. This can be seen already now in ZCML: 
whenever packages are moved, a lot of search and replace must be done on 
existing configuration files. Using interface names (with the entire 
package page) in an XML export does not guarantee that the data will be 
usable in upcoming versions of the same application. We are not even 
talking about trans-typing, but just about tracking resource types that 
change names. The positive aspect about interfaces is that it is 
possible to query the type of an object using

   queryType(object, InterfaceType)

to get the type of the object.

The solution sketched here tries to combine the advantage of dotted 
names with the flexibility of interfaces.

First we do a categorization of resources according to three different 
types. In cpsskins we have:

IElementType, IResourceType, IContentType

IElementType is a first-level categorization, IResourceType a 
second-level categorization and IContentType is a third level (it is 
zope.app.content.interfaces.IContentType). There could be more levels, 
but this is enough for now.

Typically portlets are part of a 'canvas' so their element type is 
'canvas', their resource type is 'portlet' and their content type is for 
instance 'cpsskins.actions', so the URI of a portlet would be:

   'canvas-portlet-cpsskins.actions-12345'

(if '12345' is the identifier of the portlet instance)

which we can obtain directly with:

   IIdentifiable(resource).getURI()

Let us say we have a 'widget', -- in cpsskins a "format element" because 
it adds a format to displayed elements, then it will be identified as:

   'format-widget-cpsskins.somewidget-12345'

whereas a widget in the context of a form would be identified as:

   'form-widget-formlib.textinput-12345'


the names between the '-' signs are tagged names attached to interfaces. 
It doesn't matter if two different interfaces have the same name since 
unicity is created by combining the names. For instance we have:

   resource = Style()
   resource_type = queryType(resource, IResourceType)
   resource_type.getTaggedValue('name')
   => u'style'

   or one can also write:

   IType(resource).resourcename

So a short name is associated to an interface type that is the basis for 
creating a URI, and conversely it is possible to match URIs to interfaces:

for instance  IActionPortlet ('cpsskins.actions') extends ICanvas 
('canvas') and IPortlet ('portlet'), and ActionPortlet implements all three.

The association IActionPortlet <-> IContentType is done with:

   alsoProvides(IActionPortlet,  IContentType)

when the resource is defined.
then we have:

   alsoProvides(IPortlet,  IResourceType)
   alsoProvides(ICanvas,  IElementType)

[...]

So basically and to summarize: it is the application's responsibility to 
categorize resources by type and to generate URIs from these, not the 
developer's responsibility.
 
any thoughts?
regards /JM


More information about the Zope3-dev mailing list