<html xmlns:lxslt="http://xml.apache.org/xslt" xmlns:saxon="http://icl.com/saxon" xmlns:xalanredirect="org.apache.xalan.xslt.extensions.Redirect"><head>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>2. ACS 4 Data Models and the Object System</title><link rel="stylesheet" href="ad.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.24"><link rel="home" href="index.html" title="ACS Core"><link rel="up" href="dev-guide.html" title="4. ACS Developer's Guide"><link rel="previous" href="dev-guide.html" title="4. ACS Developer's Guide"><link rel="next" href="packages.html" title="3. ACS 4 Packages"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><a href="http://www.arsdigita.com/"><img src="images/arsdigita.gif" border="0" width="73" height="65"></a><br><br><a class="topnav" href="/">Home</a><span class="topnav"> : </span><a class="topnav" href="index">Documentation</a><span class="topnav"> : </span><a class="topnav" href="acs-dev.html">Part III. For ACS Developers</a><span class="topnav"> : </span><a class="topnav" href="dev-guide.html">4. ACS Developer's Guide</a><span class="topnav"> : </span><strong class="topnav">2. ACS 4 Data Models and the Object System&nbsp;</strong><hr size="1" noshade><div id="objects" class="sect1"><div class="titlepage"><h2 class="title" style="clear: all"><a name="objects"></a><span class="label">2.</span> <span class="title">ACS 4 Data Models and the Object System</span></h2></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt>2.1. <a href="objects.html#objects-overview">Overview</a></dt><dt>2.2. <a href="objects.html#objects-how-to-use">How to Use Objects</a></dt><dt>2.3. <a href="objects.html#objects-when-to-use-objects">When to Use Objects</a></dt><dt>2.4. <a href="objects.html#objects-design-guidance">Design Guidance</a></dt><dt>2.5. <a href="objects.html#objects-summary">Summary</a></dt></dl></div><p><p>By <a href="mailto:psu@arsdigita.com" target="_top">Pete Su</a></p></p><div id="objects-overview" class="sect2"><div class="titlepage"><h3 class="title"><a name="objects-overview"></a><span class="label">2.1.</span> <span class="title">Overview</span></h3></div><p>
Developing data models in ACS 4 is much like developing data models
for ACS 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
application, we have to be able to keep track of who entered a
particular note, when they did it, and the actual text of the notes
that users have entered.  A simple data model might look like this:
</p><blockquote><table border="0" cellpadding="5" cellspacing="0"><tr><td class="codeblock"><pre>
create table notes (
    note_id integer primary key,
    owner_id integer references users(user_id),
    creation_user references(user_id) not null,
    creation_date date not null,
    last_modified date not null,
    title varchar(255) not null,
    body varchar(1024)
)
</pre></td></tr></table></blockquote><p>
We've omitted constraint names for the purpose of clarity.
</p><p>
Thinking further ahead, we can imagine doing any of the following
things with Notes as well:
</p><div class="itemizedlist"><ul><li style="list-style-type: opencircle"><a name="N4773"></a><p>Define access control policies on notes.</p></li><li style="list-style-type: opencircle"><a name="N4776"></a><p>Attach user comments on notes.</p></li><li style="list-style-type: opencircle"><a name="N4779"></a><p>Allows users to define custom fields to store on their notes.</p></li><li style="list-style-type: opencircle"><a name="N4782"></a><p>Automatically generate input forms or output displays for notes.</p></li><li style="list-style-type: opencircle"><a name="N4785"></a><p>Allow other applications to use notes in ways we don't know of yet.</p></li></ul></div><p>
In ACS 4, the key to enabling these types of services on your
application data is to take advantage of the Object System.  The first
question anyone asks is usually "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 ACS 4, or that may be reusable in
the context of future applications. Every object in the system is
represented using a row in the <tt>acs_objects</tt> 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.
</p><p>
To make use of the object system, you as the application developer
have to write your data model in a way that is slightly more complex
than before. What you get for this extra work includes:

<div class="itemizedlist"><ul><li><a name="N4797"></a><p>The <a href="permissions.html">Permissions System</a> 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.</p></li><li><a name="N4803"></a><p>Every object has an attribute called <tt>context_id</tt>
      that provides a way to trivially specify both the default
      permissions for an object, and the intended "scope" of an
      object. Just set the <tt>context_id</tt> to the controlling
      object and forget about it.</p></li><li><a name="N4814"></a><p>And most importantly, any future object-level service - from
      a general-comments replacement to personalized ranking - will
      become available to your application "for free."</p></li></ul></div>
</p></div><div id="objects-how-to-use" class="sect2"><div class="titlepage"><h3 class="title"><a name="objects-how-to-use"></a><span class="label">2.2.</span> <span class="title">How to Use Objects</span></h3></div><p>
Using ACS objects is straightforward: all that's required are a few
extra steps in the design of your application data model. 
</p><p>
For our example Notes application, to hook into the object system we
make some calls to use our <tt>notes</tt> table as the basis for a
new <i>object type</i>. Object types are analogous to classes in
programming languages such as C++ and Java. For example, in Java a
class defines a set of attributes that store data and a set of methods
that run code. In ACS 4, we use one or more Oracle tables to store the
data attributes, and we define a PL/SQL package to hold procedures to
define the programming interface to the data model.
</p><p>
The object type itself is described using data in the
<tt>acs_object_types</tt> and <tt>acs_attributes</tt> tables,
which plays 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. Given all of this,
below you'll find the code needed to describe a new object type called
<tt>notes</tt> in your system.
</p><p>
Fire up your text editor and open the
<tt>ROOT/packages/notes/sql/notes-create.sql</tt> file created
during the earlier <a href="packages.html">created the package</a>.  Then, do the following:
</p><div id="N4857" class="sect3"><div class="titlepage"><h4 class="title"><a name="N4857"></a><span class="label">2.2.1.</span> <span class="title">Describe the new type to the type system</span></h4></div><p>
First, add an entry to the <tt>acs_object_types</tt> table with the following PL/SQL call:
</p><blockquote><table border="0" cellpadding="5" cellspacing="0"><tr><td class="codeblock"><pre>
begin  
  acs_object_type.create_type ( 
    supertype     =&gt; 'acs_object', 
    object_type   =&gt; 'note', 
    pretty_name   =&gt; 'Note', 
    pretty_plural =&gt; 'Notes', 
    table_name    =&gt; 'NOTES', 
    id_column     =&gt; 'NOTE_ID' 
  ); 
end;
/
show errors;
</pre></td></tr></table></blockquote><p>
This PL/SQL call tells the system that we would like to use the table
<tt>NOTES</tt> as the basis for a new object type called
<tt>note</tt>. This type is a subtype of the 
<tt>acs_object</tt> 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 <tt>acs_object</tt>.
</p><p>
Now add entries to the <tt>acs_attributes</tt> 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 <tt>notes</tt> table, though that functionality isn't yet
available.
</p><blockquote><table border="0" cellpadding="5" cellspacing="0"><tr><td class="codeblock"><pre>
declare 
 attr_id acs_attributes.attribute_id%TYPE; 
begin
  attr_id := acs_attribute.create_attribute ( 
    object_type    =&gt; 'note', 
    attribute_name =&gt; 'TITLE', 
    pretty_name    =&gt; 'Title', 
    pretty_plural  =&gt; 'Titles', 
    datatype       =&gt; 'string' 
  ); 
 
  attr_id := acs_attribute.create_attribute ( 
    object_type    =&gt; 'note', 
    attribute_name =&gt; 'BODY', 
    pretty_name    =&gt; 'Body', 
    pretty_plural  =&gt; 'Bodies', 
    datatype       =&gt; 'string' 
  ); 
end; 
/ 
show errors; 
</pre></td></tr></table></blockquote><p>
We can stop here and not bother to register the usual ACS 3.x
attributes of <tt>creation_user</tt>, <tt>creation_date</tt>
and <tt>last_modified</tt>, since the object type
<tt>acs_object</tt> already defines these attributes. Again,
because the new type <tt>note</tt> is a subtype of
<tt>acs_object</tt>, it will inherit these attributes, so there is
no need for us to define them.
</p></div><div id="N4926" class="sect3"><div class="titlepage"><h4 class="title"><a name="N4926"></a><span class="label">2.2.2.</span> <span class="title">Define a table in which to store your objects</span></h4></div><p>
The next thing we do is make a small modification to the data model to
reflect the fact that each row in the <tt>notes</tt> table
represents something that is not only an object of type
<tt>note</tt>, but also an <tt>acs_object</tt>. The new table
definition looks like this:
</p><blockquote><table border="0" cellpadding="5" cellspacing="0"><tr><td class="codeblock"><pre>
create table notes (
    note_id integer references acs_objects(object_id) primary key,
    owner_id integer references users(user_id),
    title varchar(255) not null,
    body varchar(1024)
)
</pre></td></tr></table></blockquote><p>
Again, the usual <tt>creation_date</tt> and
<tt>modified_date</tt> columns are absent since they already exist
in <tt>acs_objects</tt>.  Also, note the constraint we have added
to reference the <tt>acs_objects</tt> table, which makes clear
that since <tt>note</tt> is a subtype of <tt>acs_object</tt>,
every row in the notes table must have a corresponding row in the
<tt>acs_objects</tt> table. This is the fundamental means by which
we model inheritance; it guarantees that any services developed that
use the <tt>acs_objects</tt> table to find objects will
transparently find any objects that are instances of any subtype of
<tt>acs_objects</tt>.
</p></div><div id="N4984" class="sect3"><div class="titlepage"><h4 class="title"><a name="N4984"></a><span class="label">2.2.3.</span> <span class="title">Define a package for type specific procedures</span></h4></div><p>
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:
</p><blockquote><table border="0" cellpadding="5" cellspacing="0"><tr><td class="codeblock"><pre>
create or replace package note 
as 
  function new ( 
    note_id             in notes.note_id%TYPE default null, 
    owner_id            in notes.owner_id%TYPE default null, 
    title               in notes.title%TYPE, 
    body                in notes.body%TYPE, 
    object_type         in acs_object_types.object_type%TYPE default 'note', 
    creation_date       in acs_objects.creation_date%TYPE 
                           default sysdate, 
    creation_user       in acs_objects.creation_user%TYPE 
                           default null, 
    creation_ip         in acs_objects.creation_ip%TYPE default null, 
    context_id          in acs_objects.context_id%TYPE default null 
  ) return notes.note_id%TYPE; 
 
  procedure delete ( 
    note_id      in notes.note_id%TYPE 
  ); 
end note; 
/ 
show errors 
</pre></td></tr></table></blockquote><p>
You might be wondering what all the extra parameters are to these
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 ACS 4 Object
System defines these attributes on the type <tt>acs_object</tt>
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
ACS 3.x data models, with the exception of the <tt>context_id</tt>
attribute.
</p><p>
The <tt>context_id</tt> attribute stores the ID of an object that
represents the default security domain to which the object belongs. It
is used by the <a href="permissions.html">permissions</a> 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 <a href="permissions.html">permissions</a> 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.
</p></div><div id="N5016" class="sect3"><div class="titlepage"><h4 class="title"><a name="N5016"></a><span class="label">2.2.4.</span> <span class="title">Define a package body for type specific procedures</span></h4></div><p>
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
<tt>acs_object.new</tt> to insert a row into
<tt>acs_objects</tt>, before inserting a row into the
<tt>notes</tt>. Similarly, when we delete a row from
<tt>note</tt>, we have to be sure to delete the corresponding
<tt>acs_object</tt> row.
</p><blockquote><table border="0" cellpadding="5" cellspacing="0"><tr><td class="codeblock"><pre>
create or replace package body note 
as 
 
  function new ( 
    note_id             in notes.note_id%TYPE default null, 
    owner_id            in notes.owner_id%TYPE default null, 
    title               in notes.title%TYPE, 
    body                in notes.body%TYPE, 
    object_type         in acs_object_types.object_type%TYPE default 'note', 
    creation_date       in acs_objects.creation_date%TYPE 
                           default sysdate, 
    creation_user       in acs_objects.creation_user%TYPE 
                           default null, 
    creation_ip         in acs_objects.creation_ip%TYPE default null, 
    context_id          in acs_objects.context_id%TYPE default null 
  ) return notes.note_id%TYPE 
  is 
    v_note_id integer; 
  begin 
    v_note_id := acs_object.new ( 
      object_id     =&gt; note_id, 
      object_type   =&gt; object_type, 
      creation_date =&gt; creation_date, 
      creation_user =&gt; creation_user, 
      creation_ip   =&gt; creation_ip, 
      context_id    =&gt; context_id 
    ); 
    
    insert into notes 
     (note_id, owner_id, title, body) 
    values 
     (v_note_id, owner_id, title, body); 
 
     return v_note_id; 
  end new; 
  
  procedure delete ( 
    note_id      in notes.note_id%TYPE 
  ) 
  is 
  begin 
    delete from notes 
    where note_id = note.delete.note_id; 
 
    acs_object.delete(note_id); 
  end delete; 
 
end note; 
/ 
show errors; 
</pre></td></tr></table></blockquote><p>
That's pretty much it! As long as you use the <tt>note.new</tt>
function to create notes, and the <tt>note.delete</tt> function to
delete them, you'll be assured that the relationship each
<tt>note</tt> has with its corresponding <tt>acs_object</tt>
is preserved.
</p><p>
The last thing to do is to make a file
<tt>ROOT/packages/notes/sql/notes-drop.sql</tt> so it's easy to
drop the data model when, say, you're testing:
</p><blockquote><table border="0" cellpadding="5" cellspacing="0"><tr><td class="codeblock"><pre>
begin 
  acs_object_type.drop_type ('note'); 
end; 
/ 
show errors 
 
drop package note; 
drop table notes; 
</pre></td></tr></table></blockquote></div></div><div id="objects-when-to-use-objects" class="sect2"><div class="titlepage"><h3 class="title"><a name="objects-when-to-use-objects"></a><span class="label">2.3.</span> <span class="title">When to Use Objects</span></h3></div><p>
While it is generally 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:
</p><p>
Anything in your data model that needs to be available to general ACS
services such as user comments, permissions, and so on should be a
subtype of <tt>acs_object</tt>. In addition, if you want your data
model to take advantage of attributes that exist in some object type
that is a subtype of <tt>acs_object</tt>, then you should use the
object system.
</p><p>
For example, for most applications, you will want to use objects to
represent the data in your application that is user visible and thus
requires access control. But other internal tables, views, mapping
tables and so on probably don't need to be objects. As before, this
kind of design decision is mostly made on an
application-by-application basis, but this is a good baseline from
which to start.
</p></div><div id="objects-design-guidance" class="sect2"><div class="titlepage"><h3 class="title"><a name="objects-design-guidance"></a><span class="label">2.4.</span> <span class="title">Design Guidance</span></h3></div><p>
In this section we cover some overall guidelines for designing data
models that are meant to be integrated with the ACS object
system. 
</p><p>
There are two basic rules you should follow when designing ACS 4 data
models:


<div class="orderedlist"><ol type="1"><li><a name="N5101"></a><p>
Never utilize fields in the <tt>acs_objects</tt> table in
application specific ways. That is, never assign any
application-specific semantics to this data.  In the notes
application, we use the <tt>creation_date</tt> and
<tt>last_modified</tt> fields, but this is OK since we do not
assign any application-specific meaning to these fields.
</p></li><li><a name="N5116"></a><p>
In particular, never assign any application specific semantics to the
<tt>context_id</tt> attribute of an object. This field is used for
a very specific purpose by the permissions system, and using this
field in <i>any other way whatsoever</i> is guaranteed to make your
application act strangely.
</p><p>
As we'll see later, the Notes example will point each note object's
<tt>context_id</tt> 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,
and the administrator would be able to use the package instance as
the basis for access control, which is convenient.
</p></li></ol></div>


The reason behind these two rules is pretty straightforward: First,
the ACS Object system itself is meant to be a generic and reusable
tool for any application to use for basic services. Second, in order
for this to work, the various parts of the ACS Objects data model must
be interpreted in the same way by all applications that use the data
model. Therefore, assigning any application-specific semantics to any
part of the core data model is a bad thing to do, because then the
semantics of the data model are no longer independent of the
application. This would make it impossible to build the generic tools
that the data model is trying to support.
</p><p>
Another less important reason for these two rules is to not introduce
any joins against the <tt>acs_objects</tt> table in SQL queries in
your application that you do not absolutely need. 
</p><p>
In the Notes example,  the result of applying these rules is that we
are careful to define our own attribute for <tt>owner_id</tt>
rather than overloading <tt>creation_user</tt> from the objects
table. But, since we will probably use <tt>creation_date</tt> 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
<tt>acs_objects</tt> 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.
</p></div><div id="objects-summary" class="sect2"><div class="titlepage"><h3 class="title"><a name="objects-summary"></a><span class="label">2.5.</span> <span class="title">Summary</span></h3></div><p>
Hooking into the ACS 4 object system brings the application developer
numerous benefits, and doing it involves only four easy steps:


<div class="itemizedlist"><ul><li style="list-style-type: opencircle"><a name="N5165"></a><p>
Describe the a new object type to the system. Most new application
types will be subtypes of the built-in type <tt>acs_object</tt>.
</p></li><li style="list-style-type: opencircle"><a name="N5172"></a><p>
Define a table to store application object data.
</p></li><li style="list-style-type: opencircle"><a name="N5175"></a><p>
Define a PL/SQL package to store procedures related to the new
type. You have to define at least a function called <tt>new</tt>
to create new application objects and a procedure called
<tt>delete</tt> to delete them.
</p></li><li style="list-style-type: opencircle"><a name="N5186"></a><p>
Define a package body that contains the implementations of the PL/SQL
procedures defined above.
</p></li><li style="list-style-type: opencircle"><a name="N5189"></a><p>
Try not to write queries in your application that join against
<tt>acs_objects</tt>. This means you should never use the fields
in <tt>acs_objects</tt> for application-specific purposes. This is
especially true for the <tt>context_id</tt> field.
</p></li></ul></div>

</p><p><div align="right" class="cvstag">($Id: objects.html,v 1.1.1.1 2001/03/13 22:59:26 ben Exp $)</div></p></div></div><div class="navfooter"><hr size="1" noshade><table width="100%"><tr><td width="40%" align="left"><a class="bottomnav" href="dev-guide.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a href="mailto:acs-docs@arsdigita.com"><address class="nav">acs-docs@arsdigita.com</address></a></td><td width="40%" align="right">&nbsp;<a class="bottomnav" href="packages.html">Next</a></td></tr></table></div></body></html>