Index: openacs-4/packages/acs-core-docs/www/object-system-design.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/object-system-design.html,v diff -u -r1.26 -r1.27 --- openacs-4/packages/acs-core-docs/www/object-system-design.html 16 Feb 2005 00:21:03 -0000 1.26 +++ openacs-4/packages/acs-core-docs/www/object-system-design.html 4 Jun 2006 00:45:24 -0000 1.27 @@ -1,4 +1,5 @@ -
By Pete Su, Michael Yoon, Richard Li, Rafael Schloming
+ +By Pete Su, Michael Yoon, Richard Li, Rafael Schloming
OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff.All of these services involve relating additional service-related information to application data objects. Examples of application objects include:
forum messages
A user home page
A ticket in the ticket tracker
In the past, developers had to use ad-hoc and inconsistent schemes to -interface to various "general" services. OpenACS 4 defines a central +interface to various "general" services. OpenACS 4 defines a central data model that keeps track of the application objects that we wish to manage, and serves as a primary store of metadata. By metadata, we mean data stored on behalf of an application @@ -49,14 +50,14 @@ user_group_map table as a way to identify data associated with a single membership relation.
Also, in OpenACS 3.x many utility modules exist that do nothing more than attach some extra attributes to existing application data. For example, -general comments maintains a table that maps application "page" +general comments maintains a table that maps application "page" data (static or dynamic pages on the website) to one or more user comments on that page. It does so by constructing a unique identifier for each page, usually a combination of the table in which the data is stored, and the value of the primary key value for the particular page. This idiom is referred to -as the "(on_which_table + on_what_id)" method for identifying +as the "(on_which_table + on_what_id)" method for identifying application data. In particular, general comments stores its map from pages -to comments using a "(on_which_table + on_what_id)" key plus the ID +to comments using a "(on_which_table + on_what_id)" key plus the ID of the comment itself.
All of these composite key constructions are implicit object identifiers - they build a unique ID out of other pieces of the data model. The problem is that their definition and use is ad-hoc and inconsistent, making the @@ -72,13 +73,13 @@ make sure every object the system is to manage is associated with a row in acs_objects. More importantly, if they do this, new services like general comments can be created without requiring existing applications -to "hook into" them via new metadata.
Note: Object identifiers are a good example of metadata +to "hook into" them via new metadata.
Note: Object identifiers are a good example of metadata in the new system. Each row in acs_objects stores information about the application object, but not the application object itself. This becomes more clear if you skip ahead and look at the SQL schema code that defines this table.
Until the implementation of the general permissions system, every OpenACS application had to manage access control to its data separately. Later on, a -notion of "scoping" was introduced into the core data model.
"Scope" is a term best explained by example. Consider some +notion of "scoping" was introduced into the core data model.
"Scope" is a term best explained by example. Consider some hypothetical rows in the address_book table:
... | scope | user_id | group_id | ... |
... | user | 123 | � | ... |
... | group | � | 456 | ... |
... | public | � | � | ... |
The first row represents an entry in User 123's personal address book, the second row represents an entry in User Group 456's shared address book, and the third row represents an entry in the site's public address @@ -95,8 +96,8 @@ easier to break the site up into security domains according to its natural structure. An object's context is stored in the context_id column of the acs_objects table.
We use an object's context to provide a default answer to questions -regarding access control. Whenever we ask a question of the form "can -user X perform action Y on object Z", the OpenACS security model will defer +regarding access control. Whenever we ask a question of the form "can +user X perform action Y on object Z", the OpenACS security model will defer to an object's context if there is no information about user X's permission to perform action Y on object Z.
The context system forms the basis for the rest of the OpenACS access control system, which is described in in two separate documents: one for the permissions system and another for the @@ -109,7 +110,7 @@ along with attributes to be stored with each instance of a group type. Each group type could define a helper table that stored attributes on each instance of the group type. This table was called the -"_info" table because the name was generated by +"_info" table because the name was generated by appending _info to the name of the group type.
The user/groups data model also provided the user_group_type_member_fields and user_group_member_fields tables to define attributes for members @@ -130,7 +131,7 @@ The motivation for subtypes comes from the need for OpenACS to be more extensible. In OpenACS 3.x, many applications extended the core data models by directly adding more columns, in order to provide convenient access to new -information. This resulted in core data tables that were too "fat", +information. This resulted in core data tables that were too "fat", containing a hodge podge of unrelated information that should have been normalized away. The canonical example of this is the explosion of the users table in OpenACS 3.x. In addition to being sloppy technically, @@ -146,19 +147,19 @@ second consisted of two tables, one describing attributes and one storing values, to provide a flexible means for attaching attributes to metadata objects. This style of attribute storage is used in several other parts of -OpenACS 3.x, and we will refer to it as "skinny tables". For +OpenACS 3.x, and we will refer to it as "skinny tables". For example:
In the Ecommerce data model, the ec_custom_product_fields table defines attributes for catalog products, and the ec_custom_product_field_values table stores values for those attributes.
In the Photo DB data model, the ph_custom_photo_fields table defines attributes for the photographs owned by a specific user, and tables named according to the convention -"ph_user_<user_id>_custom_info" are used to +"ph_user_<user_id>_custom_info" are used to store values for those attributes.
In addition, there are some instances where we are not using this model but should, e.g. the users_preferences table, which stores preferences for registered users in columns such as prefer_text_only_p and dont_spam_me_p. The -"standard" way for an OpenACS 3.x-based application to add to the list +"standard" way for an OpenACS 3.x-based application to add to the list of user preferences is to add a column to the users_preferences table (exactly the kind of data model change that has historically complicated the process of upgrading to a more recent OpenACS version).
The Objet Model generalizes the scheme used in the old OpenACS 3.x user/groups @@ -187,16 +188,16 @@ of acs_object, extended with extra attributes that store constraints on the relation, and the types of objects the relation actually maps. In turn, each instance of a relation type is an object that represents -a single fact of the form "the object t of type T is related to the -object r of type R." That is, each instance of a relation type is +a single fact of the form "the object t of type T is related to the +object r of type R." That is, each instance of a relation type is essentially just a pair of objects.
Relation types generalize mapping tables. For example, the 3.x user/groups data model can be largely duplicated using a single relation type describing -the "group membership" relation. Group types would then be subtypes +the "group membership" relation. Group types would then be subtypes of this membership relation type. Group type attributes would be attached to the relation type itself. Group member attributes would be attached to instances of the membership relation. Finally, the mapping table would be replaced by a central skinny table that the relation type system defines.
Relation types should be used when you want to be able to attach data to -the "fact" that object X and object Y are related to each other. On +the "fact" that object X and object Y are related to each other. On the face of it, they seem like a redundant mechanism however, since one could easily create a mapping table to do the same thing. The advantage of registering this table as a relation type is that in principle the OpenACS 4 @@ -210,15 +211,15 @@ is that all of the major object database vendors ship products that are effectively tied to some set of object oriented programming languages. Their idea is to provide tight language-level integration to lower the -"impedance mismatch" between the database and the language. +"impedance mismatch" between the database and the language. Therefore, database objects and types are generally directly modeled on language level objects and types. Of course, this makes it nearly impossible to interact with the database from a language that does not have this tight coupling, and it limits the data models that we can write to ideas that are expressible in the host language. In particular, we lose many of the best features of the relational database model. This is a disaster from an ease of use standpoint. -
The "Object relational" systems provide an interesting +
The "Object relational" systems provide an interesting alternative. Here, some notion of subtyping is embedded into an existing SQL or SQL-like database engine. Examples of systems like this include the new Informix, PostgreSQL 7, and Oracle has something like this too. The main @@ -274,16 +275,16 @@
This table contains one row for every object type in the system. The key things to note about this table are:
For every type, we store metadata for how to display this type in certain contexts (pretty_name and pretty_plural).
If the type is a subtype, then its parent type is stored in the column -supertype.
We support a notion of "abstract" types that contain no +supertype.
We support a notion of "abstract" types that contain no instances (as of 9/2000 this is not actually used). These types exist only to -be subtyped. An example might be a type representing "shapes" that +be subtyped. An example might be a type representing "shapes" that contains common characteristics of all shapes, but which is only used to create subtypes that represent real, concrete shapes like circles, squares, and so on.
Every type defines a table in which one can find one row for every instance of this type (table_name, id_column).
type_extension_table is for naming a table that stores extra generic attributes.
The second table we use to describe types is acs_attributes. Each row in this table represents a single attribute on a specific object -type (e.g. the "password" attribute of the "user" type). +type (e.g. the "password" attribute of the "user" type). Again, here is an abbreviated version of what this table looks like. The actual table used in the implementation is somewhat different and is discussed in a separate document.
@@ -310,15 +311,15 @@ (pretty_name, sort_order).
The data_type column stores type information on this attribute. This is not the SQL type of the attribute; it is just a human readable name for the type of data we think the attribute holds (e.g. -"String", or "Money"). This might be used later to +"String", or "Money"). This might be used later to generate a user interface.
The sort_order column stores information about how to sort -the attribute values.
Attributes can either be stored explicitly in a table ("type -specific storage") or in a skinny table ("generic storage"). +the attribute values.
Attributes can either be stored explicitly in a table ("type +specific storage") or in a skinny table ("generic storage"). In most cases, an attribute maps directly to a column in the table identified by the table_name of the corresponding object type, although, as mentioned above, we sometimes store attribute values as key-value pairs in a -"skinny" table. However, when you ask the question "What are -the attributes of this type of object?", you don't really care about +"skinny" table. However, when you ask the question "What are +the attributes of this type of object?", you don't really care about how the values for each attribute are stored (in a column or as key-value pairs); you expect to receive the complete list of all attributes.
The max_n_values and min_n_values columns encode information about the number of values an attribute may hold. @@ -328,7 +329,7 @@ types. We said above that object relationships are used to generalize the 3.x notion of group member fields. These were fields that a developer could store on each member of a group, but which were contextualized to the -membership relation. That is, they were really "attached" to the +membership relation. That is, they were really "attached" to the fact that a user was a member of a particular group, and not really attached to the user. This is a subtle but important distinction, because it allowed the 3.x system to store multiple sets of attributes on a given user, one set @@ -355,8 +356,8 @@ instances of object_type_one and instances of object_type_two. Therefore, each instance of this relation type will be a pair of objects of the appropriate types.
The role columns store human readable names for the roles -played by each object in the relation (e.g. "employee" and -"employer"). Each role must appear in the +played by each object in the relation (e.g. "employee" and +"employer"). Each role must appear in the acs_rel_roles.
The min_n_rels_one column, and its three friends allow the programmer to specify constraints on how many objects any given object can be related to on either side of the relation.
This table is easier to understand if you also know how the acs_rels table works.
To summarize, the acs_object_types and @@ -396,7 +397,7 @@ acs_static_attr_values are used to store attribute values that are not stored in a helper table associated with the object's type. The former is used for instance attributes while the latter is used for -class-wide "static" values. These tables have the same basic form, +class-wide "static" values. These tables have the same basic form, so we'll only show the first:
create table acs_attribute_values ( @@ -683,8 +684,8 @@ creating and managing relation types, and acs_rel for relating objects.These two procedures just insert and remove roles from the acs_rel_roles table. This table stores the legal relationship -"roles" that can be used when creating relation types. Examples of -roles are, say, "member", or "employer".
+"roles" that can be used when creating relation types. Examples of +roles are, say, "member", or "employer".procedure create_role ( role in acs_rel_roles.role%TYPE @@ -857,4 +858,4 @@ on par with the old user/groups system in a more general way.
Pete Su generated this document from material culled from other documents by Michael Yoon, Richard Li and Rafael Schloming. But, any remaining lies are his and his alone.