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
_______________________________________________
Zope3-dev mailing list
Zope3-dev@zope.org
Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com

Reply via email to