Index: openacs-4/packages/acs-core-docs/www/objects.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/objects.html,v diff -u -N -r1.48.2.1 -r1.48.2.2 --- openacs-4/packages/acs-core-docs/www/objects.html 18 Jun 2010 21:29:35 -0000 1.48.2.1 +++ openacs-4/packages/acs-core-docs/www/objects.html 12 Dec 2010 00:07:02 -0000 1.48.2.2 @@ -1,9 +1,19 @@ +<<<<<<< objects.html OpenACS Data Models and the Object System

OpenACS Data Models and the Object System

By Pete Su

+======= + +OpenACS Data Models and the Object System

OpenACS Data Models and the Object System

By Pete Su

+>>>>>>> 1.50 OpenACS docs are written by the named authors, and may be edited by OpenACS documentation staff. +<<<<<<< objects.html

Overview

Developing data models in OpenACS 5.6.0 is much like developing data models +======= +

Overview

+Developing data models in OpenACS 5.6.0 is much like developing data models +>>>>>>> 1.50 for OpenACS 3, save for the implementation. As usual, you need to examine how to model the information that the application must store and manipulate, and define a suitable set of SQL tables. In our Notes @@ -25,15 +35,15 @@

Thinking further ahead, we can imagine doing any of the following things with Notes as well: -

  • Define access control policies on notes.

  • Attach user comments on notes.

  • Allow users to define custom fields to store on their notes.

  • Automatically generate input forms or output displays for notes.

  • Allow other applications to use notes in ways we don't know of yet.

+

  • Define access control policies on notes.

  • Attach user comments on notes.

  • Allow users to define custom fields to store on their notes.

  • Automatically generate input forms or output displays for notes.

  • Allow other applications to use notes in ways we don't know of yet.

In OpenACS, the key to enabling these types of services on your application data is to take advantage of the Object System. The first -question, then, is "Just what are objects, and what do -you use them for anyway?". The short answer: objects are anything +question, then, is "Just what are objects, and what do +you use them for anyway?". The short answer: objects are anything represented in the application's data model that will need to be managed by any central service in OpenACS, or that may be reusable in the context of future applications. Every object in the system is -represented using a row in the acs_objects table. This +represented using a row in the acs_objects table. This table defines all the standard attributes that are stored on every object, including its system-wide unique ID, object type, and some generic auditing columns. @@ -42,22 +52,22 @@ have to write your data model in a way that is slightly more complex than in the ACS 3.x days. What you get for this extra work includes: -

  • The Permissions System lets you +

    • The Permissions System lets you track who is allowed to do what to the rows in an application table, and gives you an easy way to enforce - this from Tcl.

    • Every object has an attribute called context_id + this from Tcl.

    • Every object has an attribute called context_id that provides a way to trivially specify both the default - permissions for an object, and the intended "scope" of an - object. Just set the context_id to the controlling - object and forget about it.

    • And most importantly, any future object-level service - from + permissions for an object, and the intended "scope" of an + object. Just set the context_id to the controlling + object and forget about it.

    • And most importantly, any future object-level service - from a general-comments replacement to personalized ranking - will - become available to your application "for free."

    -

How to Use Objects

+ become available to your application "for free."

+

How to Use Objects

Using ACS objects is straightforward: all that's required are a few extra steps in the design of your application data model.

In order to hook our Notes application into the object system, we -make some calls to use our notes table as the basis for a +make some calls to use our notes table as the basis for a new object type. Object types are analogous to classes in programming languages such as C++ and Java. In Java, a class defines a set of attributes that store data and a set of methods @@ -66,21 +76,28 @@ define the programming interface to the data model.

The object type itself is described using data in the -acs_object_types and -acs_attributes tables, which play a role +acs_object_types and +acs_attributes tables, which play a role similar to the data dictionary in Oracle. As in Java, object types can inherit attributes from a parent type, so the type system forms a hierarchy. Unlike Java, Oracle does not support this inheritance transparently, so we have to make sure we add our own bookkeeping code to keep everything consistent. Below you'll find the code needed to describe a -new object type called notes in your +new object type called notes in your system.

Fire up your text editor and open the +<<<<<<< objects.html ROOT/packages/notes/sql/oracle/notes-create.sql (ROOT/packages/notes/sql/postgresql/notes-create.sql for the PG version) file created when we created the package. Then, do the following:

Describe the new type to the type system

First, add an entry to the acs_object_types table with the following PL/SQL call: +======= +ROOT/packages/notes/sql/oracle/notes-create.sql (ROOT/packages/notes/sql/postgresql/notes-create.sql for the PG version) file created +when we created the package. Then, do the following: +

Describe the new type to the type system

+First, add an entry to the acs_object_types table with the following PL/SQL call: +>>>>>>> 1.50

 begin  
   acs_object_type.create_type ( 
@@ -96,18 +113,18 @@
 show errors;
 

This PL/SQL call tells the system that we would like to use the table -NOTES as the basis for a new object type called -note. This type is a subtype of the -acs_object type, which means that we want to inherit all +NOTES as the basis for a new object type called +note. This type is a subtype of the +acs_object type, which means that we want to inherit all of the basic attributes of all ACS objects. As mentioned, it will take some work on our part to make this happen, since Oracle can't do it automatically. In general, most basic applications will define types -that are simple subtypes of acs_object. +that are simple subtypes of acs_object.

-Add entries to the acs_attributes table to describe +Add entries to the acs_attributes table to describe the data attributes of the new type. This data can eventually be used to do things like automatically generate user interfaces to manipulate -the notes table, though that functionality isn't yet +the notes table, though that functionality isn't yet available.

 declare 
@@ -133,17 +150,21 @@
 show errors; 
 

We can stop here and not bother to register the usual OpenACS 3.x -attributes of creation_user, creation_date -and last_modified, since the object type -acs_object already defines these attributes. Again, -because the new type note is a subtype of -acs_object, it will inherit these attributes, so there is +attributes of creation_user, creation_date +and last_modified, since the object type +acs_object already defines these attributes. Again, +because the new type note is a subtype of +acs_object, it will inherit these attributes, so there is no need for us to define them. +<<<<<<< objects.html

Define a table in which to store your objects

+======= +

Define a table in which to store your objects

+>>>>>>> 1.50 The next thing we do is make a small modification to the data model to -reflect the fact that each row in the notes table +reflect the fact that each row in the notes table represents something that is not only an object of type -note, but also an acs_object. The new table +note, but also an acs_object. The new table definition looks like this:

 create table notes (
@@ -153,18 +174,23 @@
     body       varchar(1024)
 )
 

-The usual creation_date and -modified_date columns are absent since they already exist -in acs_objects. Also, note the constraint we have added -to reference the acs_objects table, which makes clear -that since note is a subtype of acs_object, +The usual creation_date and +modified_date columns are absent since they already exist +in acs_objects. Also, note the constraint we have added +to reference the acs_objects table, which makes clear +that since note is a subtype of acs_object, every row in the notes table must have a corresponding row in the -acs_objects table. This is the fundamental means by which +acs_objects table. This is the fundamental means by which we model inheritance; it guarantees that any services that -use the acs_objects table to find objects will +use the acs_objects table to find objects will transparently find any objects that are instances of any subtype of +<<<<<<< objects.html acs_objects.

Define a package for type specific procedures

+======= +acs_objects. +

Define a package for type specific procedures

+>>>>>>> 1.50 The next step is to define a PL/SQL package for your new type, and write some basic procedures to create and delete objects. Here is a package definition for our new type: @@ -196,30 +222,34 @@ calls, since we haven't mentioned them before. These parameters are needed to fill out information that will be stored about the object that's not stored directly in the table you defined. The OpenACS Object -System defines these attributes on the type acs_object +System defines these attributes on the type acs_object since all objects should have these attributes. Internally, there are tables that store this information for you. Most of the data is pretty self-explanatory and reflects attributes that existed in the earlier -OpenACS 3.x data models, with the exception of the context_id +OpenACS 3.x data models, with the exception of the context_id attribute.

-The context_id attribute stores the ID of an object that +The context_id attribute stores the ID of an object that represents the default security domain to which the object belongs. It -is used by the permissions system in +is used by the permissions system in this way: if no permissions are explicitly attached to the object, then the object inherits its permissions from the context. For -example, if I had told you how to use the permissions system to specify that an -object OBJ was "read only", then any other object that used OBJ as its -context would also be "read only" by default. We'll talk about this more +example, if I had told you how to use the permissions system to specify that an +object OBJ was "read only", then any other object that used OBJ as its +context would also be "read only" by default. We'll talk about this more later. +<<<<<<< objects.html

Define a package body for type specific procedures

+======= +

Define a package body for type specific procedures

+>>>>>>> 1.50 The PL/SQL package body contains the implementations of the procedures defined above. The only subtle thing going on here is that we must use -acs_object.new to insert a row into -acs_objects, before inserting a row into the -notes. Similarly, when we delete a row from -note, we have to be sure to delete the corresponding -acs_object row. +acs_object.new to insert a row into +acs_objects, before inserting a row into the +notes. Similarly, when we delete a row from +note, we have to be sure to delete the corresponding +acs_object row.

 create or replace package body note 
 as 
@@ -272,14 +302,14 @@
 / 
 show errors; 
 

-That's pretty much it! As long as you use the note.new -function to create notes, and the note.delete function to +That's pretty much it! As long as you use the note.new +function to create notes, and the note.delete function to delete them, you'll be assured that the relationship each -note has with its corresponding acs_object +note has with its corresponding acs_object is preserved.

The last thing to do is to make a file -ROOT/packages/notes/sql/notes-drop.sql so it's easy to +ROOT/packages/notes/sql/notes-drop.sql so it's easy to drop the data model when, say, you're testing:

 begin 
@@ -290,17 +320,17 @@
  
 drop package note; 
 drop table notes; 
-

When to Use Objects

+

When to Use Objects

While it is hard to give general design advice without knowing anything about a particular application, you should follow the following rule of thumb when deciding when to hook part of your data model to the object system:

Anything in your data model that needs to be available to general OpenACS services such as user comments, permissions, and so on should be a -subtype of acs_object. In addition, if you want your data +subtype of acs_object. In addition, if you want your data model to take advantage of attributes that exist in some object type -that is a subtype of acs_object, then you should use the +that is a subtype of acs_object, then you should use the object system.

For example, for most applications, you will want to use objects to @@ -310,7 +340,7 @@ kind of design decision is mostly made on an application-by-application basis, but this is a good baseline from which to start. -

Design Guidance

+

Design Guidance

In this section we cover some overall guidelines for designing data models that are meant to be integrated with the OpenACS object system. @@ -319,25 +349,25 @@ models: -

  1. -Never utilize fields in the acs_objects table in +

    1. +Never utilize fields in the acs_objects table in application specific ways. That is, never assign any application-specific semantics to this data. In the notes -application, we use the creation_date and -last_modified fields, but this is OK since we do not +application, we use the creation_date and +last_modified fields, but this is OK since we do not assign any application-specific meaning to these fields. -

    2. +

    3. In particular, never assign any application specific semantics to the -context_id attribute of an object. This field is used for +context_id attribute of an object. This field is used for a very specific purpose by the permissions system, and using this field in any other way whatsoever is guaranteed to make your application act strangely.

      As we'll see later, the Notes example will point each note object's -context_id to the package instance in which the note was +context_id to the package instance in which the note was created. The idea will be that in a real site, the administrator would create one package instance for every separate set of Notes (say, one -per user). The instance would "own" all of the notes that it created, +per user). The instance would "own" all of the notes that it created, and the administrator would be able to use the package instance as the basis for access control, which is convenient.

    @@ -355,43 +385,52 @@ that the data model is trying to support.

    Another less important reason for these two rules is to not introduce -any joins against the acs_objects table in SQL queries in +any joins against the acs_objects table in SQL queries in your application that you do not absolutely need.

    In the Notes example, the result of applying these rules is that we -are careful to define our own attribute for owner_id -rather than overloading creation_user from the objects -table. But, since we will probably use creation_date and +are careful to define our own attribute for owner_id +rather than overloading creation_user from the objects +table. But, since we will probably use creation_date and so on for their intended purposes, we don't bother to define our own attributes to store that data again. This will entail joins with -acs_objects but that's OK because it makes the overall +acs_objects but that's OK because it makes the overall data model cleaner. The real lesson is that deciding exactly how and when to use inherited attributes is fairly straightforward, but requires a good amount of thought at design time even for simple applications. +<<<<<<< objects.html

Summary

Hooking into the OpenACS 5.6.0 object system brings the application developer +======= +

Summary

+Hooking into the OpenACS 5.6.0 object system brings the application developer +>>>>>>> 1.50 numerous benefits, and doing it involves only four easy steps: -

  • +

    • Describe the a new object type to the system. Most new application -types will be subtypes of the built-in type acs_object. -

    • +types will be subtypes of the built-in type acs_object. +

    • Define a table to store application object data. -

    • +

    • Define a PL/SQL package to store procedures related to the new -type. You have to define at least a function called new +type. You have to define at least a function called new to create new application objects and a procedure called -delete to delete them. -

    • +delete to delete them. +

    • Define a package body that contains the implementations of the PL/SQL procedures defined above. -

    • +

    • Try not to write queries in your application that join against -acs_objects. This means you should never use the fields -in acs_objects for application-specific purposes. This is -especially true for the context_id field. +acs_objects. This means you should never use the fields +in acs_objects for application-specific purposes. This is +especially true for the context_id field.

    +<<<<<<< objects.html

    ($Id$)
View comments on this page at openacs.org
+======= +

($Id$)
View comments on this page at openacs.org
+>>>>>>> 1.50