Index: openacs.org-dev/packages/acs-core-docs/www/acs-admin.html =================================================================== RCS file: /usr/local/cvsroot/openacs.org-dev/packages/acs-core-docs/www/acs-admin.html,v diff -u -r1.1.1.1 -r1.1.1.2 --- openacs.org-dev/packages/acs-core-docs/www/acs-admin.html 9 Jul 2002 17:34:57 -0000 1.1.1.1 +++ openacs.org-dev/packages/acs-core-docs/www/acs-admin.html 11 Aug 2002 00:42:48 -0000 1.1.1.2 @@ -1,80 +1,4 @@ - -
- -Help to the folks keeping an OpenACS installation up and running.
-Table of Contents
- -This is the place to look if you want to extend OpenACS and build on top - of what's already here. Here you can find out about the guts of the system.
-Table of Contents
-+
Mat Kovach is graciously maintaining an AOLServer distribution that includes all the patches and modules needed to run OpenACS 4.5. These instructions will describe how to install using his source distribution. He also has binaries for SuSE 7.3 and OpenBSD 2.8 (and perhaps more to come), currently located at uptime.openacs.org. -
-+
It's also possible to download all the pieces and patches yourself: -
-+
AOLServer is available at aolserver.com -
+
ArsDigita's AOLServer distribution (including internationalization patches, nscache, nsrewrite, nssha1 and the oracle driver) is available at arsdigita.com -
+
The OpenACS PostgreSQL driver is available from OpenACS -
+
nsxml is available at http://acs-misc.sourceforge.net. -
+
The patch that makes exec work on BSD is available at sourceforge.net -
+
The patch that makes ns_uuencode work for binary files is available at sourceforge.net -
+
The patch that makes AOLServer respect the -g flag is available at sourceforge.net -
+
.... or just Download Mat's AOLServer distribution to /tmp -
-+joeuser:~$ cd /tmp joeuser:/tmp$ wget -c http://uptime.openacs.org/aolserver-openacs/aolserver3.3ad13-oacs1-beta-src.tar.gz -joeuser:/tmp$ cd-+joeuser:/tmp$ cd
As root, untar aolserver3.3ad13-oacs1-beta-src.tar.gz into /usr/local/src -
-+joeuser:~$ su - Password: ********** root:~$ cd /usr/local/src -root:/usr/local/src# tar xzf /tmp/aolserver3.3ad13-oacs1-beta-src.tar.gz-
+root:/usr/local/src# tar xzf /tmp/aolserver3.3ad13-oacs1-beta-src.tar.gz
You will need a special user account for running AOLServer. This user will be called nsadmin and belong - top the special group web. + to the special group web. nsadmin's home directory will be /usr/local/aolserver.You must execute these steps as root. -
-+
Run these commands: -
-+root:/usr/local/src# cd root:~# groupadd nsadmin root:~# groupadd web @@ -115,33 +69,23 @@ root:~# mkdir -p /web /usr/local/aolserver root:~# chown -R nsadmin.web /usr/local/aolserver /web /usr/local/src/aolserver root:~# chmod 775 /usr/local/aolserver /web -root:~# exit-
At this point, you should customize the nsadmin login scripts. Login as nsadmin and add the following lines to your /usr/local/aolserver/.bash_profile: -
-+joeuser:~$ su - nsadmin Password: *********** -nsadmin:~$ emacs .bash_profile-+nsadmin:~$ emacs .bash_profile
Add the first set of lines, if you're using Oracle. The 2nd set - of lines, if you're using PostgreSQL. Oracle - Note: These environment variables are specific for a + of lines, if you're using PostgreSQL. Oracle + Note: These environment variables are specific for a local Oracle installation communicating via IPC. If you are connecting to a remote Oracle installation, you'll need to adjust these appropriately. Also, make sure that the '8.1.7' matches your Oracle version. -
-+# For Oracle export ORACLE_BASE=/ora8/m01/app/oracle export ORACLE_HOME=$ORACLE_BASE/product/8.1.7 @@ -153,34 +97,25 @@ # For PostgreSQL export PATH=$PATH:/usr/local/pgsql/bin -export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib-+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/pgsql/lib
Be absolutely certain that you have entered these lines correctly and that you have saved the file - a slight error in these lines can lead to many inscrutable error messages. Logout and log back in so these settings will take effect. Use the echo command to be sure that the environment variables have been properly assigned. -
-+nsadmin:~$ exit joeuser:~$ su - nsadmin Password: ********* nsadmin:~$ echo $PATH ...some other directory paths...:/usr/local/pgsql/bin nsadmin:~$ echo $LD_LIBRARY_PATH -:/usr/local/pgsql/lib-+:/usr/local/pgsql/lib
Note: The result should be different if you're using Oracle. /ora8/m01/app/oracle/product/8.1.7 should have been in $PATH. -
-In order for nsxml to compile, you need libxml2 (available from http://xmlsoft.org). On Debian, @@ -189,103 +124,62 @@ download rpms from ftp.gnome.org. You'll need the libxml2 and libxml2-devel packages. -
-Prepare the distribution
-+
Prepare the distribution
nsadmin:~$ cd /usr/local/src/aolserver nsadmin:/usr/local/src/aolserver$ ./conf-clean cat: BUILD-MODULES: No such file or directory -Done.-
+Done.
Put the name of the driver(s) that you want into conf-db. This can be "postgresql", "oracle", or the word "both" if you want both drivers installed. -
--nsadmin:/usr/local/src/aolserver$ echo "postgresql" > conf-db-
+
+nsadmin:/usr/local/src/aolserver$ echo "postgresql" > conf-db
conf-inst should contain the location where AOLserver is to be installed. This defaults to /usr/local/aolserver, so we don't need to change it. -
+
conf-make should contain the name of the GNU Make command on your system. It defaults to gmake. You may need to change this to make. -
--nsadmin:/usr/local/src/aolserver$ echo "make" > conf-make-
+
+nsadmin:/usr/local/src/aolserver$ echo "make" > conf-make
If you're going to be installing the Postgresql driver, you'll have to adjust the makefile first. This will hopefully be cleaned up in future versions of this distribution. -
--nsadmin:/usr/local/src/aolserver$ emacs pgdriver/makefile-
+
+nsadmin:/usr/local/src/aolserver$ emacs pgdriver/makefile
Edit the lines containing PGLIB and PGINC so they look like this: -
-+PGINC=/usr/local/pgsql/include -PGLIB=/usr/local/pgsql/lib-
Compile and install AOLserver and modules
--nsadmin:/usr/local/src/aolserver$ ./conf-
+PGLIB=/usr/local/pgsql/lib
Compile and install AOLserver and modules
+nsadmin:/usr/local/src/aolserver$ ./conf
This takes about 5 minutes. All of the results are logged to files in /usr/local/src/aolserver/log. Make sure to check these files to see if any errors occurred. -
-You will now test to ensure AOLserver is running correctly. We'll use the sample config file provided with AOLserver. This file will attempt to guess your IP address and hostname. It will then set up the server at port 8000 of that IP address. -
-+nsadmin:/usr/local/src/aolserver$ cd -nsadmin:~$ ./bin/nsd -t sample-config.tcl-+nsadmin:~$ ./bin/nsd -t sample-config.tcl
As the AOLserver daemon starts up, you should see a few normal warnings (listed below), which are safe to ignore. -
-+Warning: nsd.tcl: nsssl not loaded -- key/cert files do not exist. -Warning: nsd.tcl: nscp not loaded -- user/password is not set.-+Warning: nsd.tcl: nscp not loaded -- user/password is not set.
The first warning means that the server is missing files for running ssl, a necessary module for encrypted HTTPS. See Scott Goodwin's excellent @@ -294,97 +188,46 @@ for administering AOLserver, could not be loaded. If you're interested in configuring nscp, please see the AOLserver documentation. -
-+
Test to see if AOLserver is working by starting Mozilla or Lynx, and surfing over to your web page: -
--nsadmin:~$ lynx localhost:8000-
+
+nsadmin:~$ lynx localhost:8000
You should see a "Welcome to AOLserver" page. If this doesn't work, try going to http://127.0.0.1:8000/. If this still doesn't work, check out the Troubleshooting AOLServer section below. -
-- Shutdown the test server:
--nsadmin:~$ killall nsd-
+
+ Shutdown the test server:
+nsadmin:~$ killall nsd
The killall command will kill all processes with the name nsd, but clearly this is not a good tool to use for managing your services in general. We cover this topic in the Keep AOLServer alive section. -
-If you can't view the welcome page, it's likely there's a problem with your server configuration. Start by viewing your AOLserver log, which is in /usr/local/aolserver/log/server.log. - You should also try to find lines of the form:
-+ You should also try to find lines of the form:[01/Jun/2000:12:11:20][5914.2051][-nssock-] Notice: nssock: listening on http://localhost.localdomain:8000 (127.0.0.1:8000) -[01/Jun/2000:12:11:20][5914.2051][-nssock-] Notice: accepting connections-If you can find these lines, try entering the URL the server is +[01/Jun/2000:12:11:20][5914.2051][-nssock-] Notice: accepting connections
If you can find these lines, try entering the URL the server is listening on. If you cannot find these lines, there must be an error somewhere in the file. Search for lines beginning with the word Error instead of - Notice.
-The sample-config.tcl file grabs - your address and hostname from your OS settings.
-+ Notice.The sample-config.tcl file grabs + your address and hostname from your OS settings.
set hostname [ns_info hostname] -set address [ns_info address]-If you get an error that nssock can't get the requested address, - you can set these manually:
-+set address [ns_info address]If you get an error that nssock can't get the requested address, + you can set these manually:
#set hostname [ns_info hostname] set hostname 127.0.0.1 #set address [ns_info address] -set address 127.0.0.1-+set address 127.0.0.1
If you get an error that nssock can't assign the requested port, then that port may already be taken by another service. Try specifying a different port in the config file. -
-Tcl API
-- -apm-install-procs.tcl (Supports installation of packages)
- -20-apm-load-procs.tcl (Bootstraps APM for server startup)
- -apm-admin-procs.tcl (Supports APM UI)
PL/SQL file
- --In general terms, a package is a unit of software that +
Tcl API
+apm-install-procs.tcl (Supports installation of packages)
+20-apm-load-procs.tcl (Bootstraps APM for server startup)
+apm-admin-procs.tcl (Supports APM UI)
PL/SQL file
+In general terms, a package is a unit of software that serves a single well-defined purpose. That purpose may be to provide a service directly to one or more classes of end-user, (e.g., discussion forums and file storage for community members, user profiling tools for the site publisher), or it may be to act as a building block for other packages (e.g., an application programming interface (API) for storing and querying access control rules, or an API for scheduling email alerts). Thus, packages fall into one of two categories: -
--OpenACS Applications: a "program or group of programs +
OpenACS Applications: a "program or group of programs designed for end users" (the Webopedia -definition); also known as modules, for historical reasons. +definition); also known as modules, for historical reasons. Examples of applications include Bboard and News. -
-OpenACS Services: the aforementioned building blocks. +
OpenACS Services: the aforementioned building blocks. Examples of services include the OpenACS Content Repository, the OpenACS Templating System, and the OpenACS Kernel, which includes -APM.
An installation of the OpenACS includes the OpenACS Kernel, some services that +APM.
An installation of the OpenACS includes the OpenACS Kernel, some services that extend the kernel's functionality, and some applications intended for end-users. Packages function as individual pieces of subsites. A subsite can contain multiple application and service instances that provide the end-user with capabilities -and content customized to the particular subsite.
-This architecture supports the growth of collaborative commerce. For +and content customized to the particular subsite.
This architecture supports the growth of collaborative commerce. For example, Jane User starts a forum focusing on the merits of View Cameras by creating an instance of the Bboard application for her personal subsite on an OpenACS Installation. Jack User discovers Jane's forum and includes a link to @@ -103,214 +42,91 @@ view cameras and a portal application that links to reliable camera models and resellers. Any subsite enabled package that is added to the OpenACS installation through APM is another potential package instance that can -become part of Jane's View Camera subsite.
-The APM provides an architecture for packaging software, making instances +become part of Jane's View Camera subsite.
The APM provides an architecture for packaging software, making instances of that software available to subsites, specifying configuration parameters -for each instance, and managing the creation and release of new packages.
-+for each instance, and managing the creation and release of new packages.
Prior to ACS 3.3, all packages were lumped together into one monolithic distribution without explicit boundaries; the only way to ascertain what comprised a given package was to look at the top of the corresponding documentation page, where, by convention, the package developer would specify where to find: -
-the data model
the Tcl procedures
the user-accessible pages
the administration pages
Experience has shown us that this lack of explicit boundaries causes a -number of maintainability problems for pre-3.3 installations:
-Package interfaces were not guaranteed to be stable in any formal way, so +
the data model
the Tcl procedures
the user-accessible pages
the administration pages
Experience has shown us that this lack of explicit boundaries causes a +number of maintainability problems for pre-3.3 installations:
Package interfaces were not guaranteed to be stable in any formal way, so a change in the interface of one package would often break dependent packages (which we would only discover through manual regression testing). In this context, any of the following could constitute an interface change: -
-renaming a file or directory that appears in a URL
changing what form variables are expected as input by a page
changing a procedural abstraction, e.g., a PL/SQL or Java stored -procedure or a Tcl procedure
changing a functional abstraction, e.g., a database view or a PL/SQL or -Java stored function
changing the data model
This last point is especially important. In most cases, changing the data -model should not affect dependent packages. Rather, the package +
renaming a file or directory that appears in a URL
changing what form variables are expected as input by a page
changing a procedural abstraction, e.g., a PL/SQL or Java stored +procedure or a Tcl procedure
changing a functional abstraction, e.g., a database view or a PL/SQL or +Java stored function
changing the data model
This last point is especially important. In most cases, changing the data +model should not affect dependent packages. Rather, the package interface should provide a level of abstraction above the data model (as well as the rest of the package implementation). Then, users of the package can take advantage of implementation improvements that don't affect the interface (e.g., faster performance from intelligent denormalization of the data model), without having to worry that code outside the package will now -break.
-A typical ACS-backed site only uses a few of the modules included in the +break.
A typical ACS-backed site only uses a few of the modules included in the distribution, yet there was no well-understood way to pick only what you needed when installing the ACS, or even to uninstall what you didn't need, post-installation. Unwanted code had to be removed manually. -
Releasing a new version of the ACS was complicated, owing again to the +
Releasing a new version of the ACS was complicated, owing again to the monolithic nature of the software. Since we released everything in the ACS together, all threads of ACS development had to converge on a single deadline, after which we would undertake a focused QA effort whose scale increased in direct proportion to the expansion of the ACS codebase. -
There was no standard way for developers outside of ArsDigita to extend +
There was no standard way for developers outside of ArsDigita to extend the ACS with their own packages. Along the same lines, ArsDigita programmers working on client projects had no standard way to keep custom development cleanly separated from ACS code. Consequently, upgrading an already installed -ACS was an error-prone and time-consuming process.
Consistent use of the APM format and tools will go a long way toward +ACS was an error-prone and time-consuming process.
Consistent use of the APM format and tools will go a long way toward solving the maintainability problems listed above. Moreover, APM is the substrate that will enable us to soon establish a central package repository, where both ArsDigita and third-party developers will be able publish their -packages for other ACS users to download and install.
-For a simple illustration of the difference between ACS without APM +packages for other ACS users to download and install.
For a simple illustration of the difference between ACS without APM (pre-3.3) and ACS with APM (3.3 and beyond), consider a hypothetical ACS installation that uses only two of the thirty-odd modules available circa ACS -3.2 (say, bboard and e-commerce):
- -APM itself is part of a package, the OpenACS Kernel, an OpenACS -service that is the only mandatory component of an OpenACS installation.
-The OpenACS is a platform for web-based application software, and any software +3.2 (say, bboard and e-commerce):
APM itself is part of a package, the OpenACS Kernel, an OpenACS +service that is the only mandatory component of an OpenACS installation.
The OpenACS is a platform for web-based application software, and any software platform has the potential to develop problems like those described above. Fortunately, there are many precedents for systematic solutions, -including:
--Debian GNU/Linux and the Debian -Packaging manual -
-FreeBSD has the Ports -collection -
Borrowing from all of the above, OpenACS 3.3 introduces its own package -management system, the OpenACS Package Manager (APM), which consists of:
--a standard format for APM packages (also called -"OpenACS packages"), including:
-version numbering, independent of any other package and the OpenACS as a -whole
specification of the package interface
specification of dependencies on other packages (if any)
attribution (who wrote it) and ownership (who maintains it)
-web-based tools for package management:
-obtaining packages from a remote distribution point
installing packages, if and only if:
-all prerequisite packages are installed
no conflicts will be created by the installation
configuring packages (obsoleting the monolithic OpenACS configuration -file)
upgrading packages, without clobbering local modifications
uninstalling unwanted packages
-a registry of installed packages, database-backed and +including:
Borrowing from all of the above, OpenACS 3.3 introduces its own package +management system, the OpenACS Package Manager (APM), which consists of:
a standard format for APM packages (also called +"OpenACS packages"), including:
version numbering, independent of any other package and the OpenACS as a +whole
specification of the package interface
specification of dependencies on other packages (if any)
attribution (who wrote it) and ownership (who maintains it)
web-based tools for package management:
obtaining packages from a remote distribution point
installing packages, if and only if:
all prerequisite packages are installed
no conflicts will be created by the installation
configuring packages (obsoleting the monolithic OpenACS configuration +file)
upgrading packages, without clobbering local modifications
uninstalling unwanted packages
a registry of installed packages, database-backed and integrated with filesystem-based version control -
-web-based tools for package development:
-creating new packages locally
releasing new versions of locally-created packages
The design chosen for APM was meant to satisfy the following constraints: -
-The process of authoring a package must be as simple as possible.
Strict conventions must be established that provide a set of canonical +
The process of authoring a package must be as simple as possible.
Strict conventions must be established that provide a set of canonical locations and names for files and patterns, for OpenACS application -development.
The processes of installing, upgrading, and using packages must be -straightforward and accessible through a web-based UI.
Package instances must be able to have subsite-specific content available -at an easily configurable URL.
All of these requirements were met, but at the cost of development +development.
The processes of installing, upgrading, and using packages must be +straightforward and accessible through a web-based UI.
Package instances must be able to have subsite-specific content available +at an easily configurable URL.
All of these requirements were met, but at the cost of development simplicity. As Packages demonstrates, a set of strict directory conventions are required in order for a package to use APM. This contrasts with the apparent simplicity available to developers of the OpenACS 3.3 system. However, while the system has become more complex for developers to build packages, this complexity is easily managed and is compensated for by additional -capabilities.
-For example, to make a new application available to the system, a -developer must:
-Create the necessary files to support the data model, Tcl API, and UI -pages.
Put the files in the correct locations for APM to be aware of them.
Use APM to create a new package and enable it.
Use the Site Map facility to create an instance of the package, mount it -on an appropriate URL, and set parameters for that particular instance.
While this is complex, especially to a new OpenACS developer, the +capabilities.
For example, to make a new application available to the system, a +developer must:
Create the necessary files to support the data model, Tcl API, and UI +pages.
Put the files in the correct locations for APM to be aware of them.
Use APM to create a new package and enable it.
Use the Site Map facility to create an instance of the package, mount it +on an appropriate URL, and set parameters for that particular instance.
While this is complex, especially to a new OpenACS developer, the documentation walks the developer through each of these steps. Moreover, from following these steps, the package can be subsite specific, available to subsites across the system, and be available for distribution to other OpenACS -installations without doing a monolithic upgrade or reinstall.
-The APM is composed of systems for accomplishing a set of package-related +installations without doing a monolithic upgrade or reinstall.
The APM is composed of systems for accomplishing a set of package-related tasks. Each of these tasks comprise a feature area that has an API, data -model, and a UI:
-Authoring a Package
Maintaining Multiple Versions of a Package
Creating Instances of the Package
Specifying Configuration Parameters for each Instance
Authoring a Package
-Full instructions on how to prepare an OpenACS package are available in Packages. The API here can be invoked manually by a package's data model +model, and a UI:
Authoring a Package
Maintaining Multiple Versions of a Package
Creating Instances of the Package
Specifying Configuration Parameters for each Instance
Authoring a Package
Full instructions on how to prepare an OpenACS package are available in Packages. The API here can be invoked manually by a package's data model creation script, but need not to be used. This API is part of the APM PL/SQL -package.
-+package.-- Informs the APM that this application is available for use. procedure register_application ( @@ -326,15 +142,12 @@ default null ); --The procedure above registers an OpenACS application in the APM. It creates a +
The procedure above registers an OpenACS application in the APM. It creates a new OpenACS object and stores information about the package, such as its name, in the APM data model. There is an analogous procedure for OpenACS services, called -apm.register_service.
-To remove an application from the system, there are the calls +apm.register_service.
To remove an application from the system, there are the calls apm.unregister_application and -apm.unregister_service.
-+apm.unregister_service.-- Remove the application from the system. procedure unregister_application ( @@ -343,29 +156,22 @@ cascade_p in char default 'f' ); --Use the cascade_p only if you want to completely remove the -package from the OpenACS.
-In order to determine if a particular package exists in the system, use +
Use the cascade_p only if you want to completely remove the +package from the OpenACS.
In order to determine if a particular package exists in the system, use the register_p predicate. It returns 1 if the specified -package_key exists in the system, 0 otherwise.
-+package_key exists in the system, 0 otherwise.function register_p ( package_key in apm_package_types.package_key%TYPE ) return integer; --Maintaining Multiple Versions of a Package
-While the package authoring API provides a means for registering a +
Maintaining Multiple Versions of a Package
While the package authoring API provides a means for registering a package, some information about a package is version dependent. For example, between versions, the owner of a package, its vendor, its URI, and its dependency information may change. The API for package versions allows this information to be specified. All of these APIs are part of the -apm_package_version PL/SQL package.
-To create a new package version, use the -apm_package_version.new constructor function.
-+apm_package_version PL/SQL package.To create a new package version, use the +apm_package_version.new constructor function.
function new ( version_id in apm_package_versions.version_id%TYPE @@ -386,49 +192,26 @@ default 'f' ) return apm_package_versions.version_id%TYPE; --In order to use this function, an existing package_key must +
In order to use this function, an existing package_key must be specified. The version_name parameter must follow a strict -convention:
-A major version number
at least one minor version number. Although any number of minor version +convention:
A major version number
at least one minor version number. Although any number of minor version numbers may be included, three minor version numbers is sufficient and is the -convention of software developers.
One of the following:
-The letter d, indicating a development-only version
The letter a, indicating an alpha release
The letter b, indicating a beta release
No letter at all, indicating a final production release
In addition, the letters d, a, and +convention of software developers.
One of the following:
The letter d, indicating a development-only version
The letter a, indicating an alpha release
The letter b, indicating a beta release
No letter at all, indicating a final production release
In addition, the letters d, a, and b may be followed by another integer, indicating a version -within the release.
-For those who like regular expressions:
-+within the release.For those who like regular expressions:
version_number := ^[0-9]+((\.[0-9]+)+((d|a|b|)[0-9]?)?)$ --So the following is a valid progression for version numbers:
--0.9d, 0.9d1, 0.9a1, 0.9b1, 0.9b2, 0.9, 1.0, 1.0.1, 1.1b1, -1.1
To delete a given version of a package, use the -apm_package_version.delete procedure:
-+So the following is a valid progression for version numbers:
0.9d, 0.9d1, 0.9a1, 0.9b1, 0.9b2, 0.9, 1.0, 1.0.1, 1.1b1, +1.1
To delete a given version of a package, use the +apm_package_version.delete procedure:
procedure delete ( package_id in apm_packages.package_id%TYPE ); --After creating a version, it is possible to edit the information -associated with it using apm_package_version.edit.
-+After creating a version, it is possible to edit the information +associated with it using apm_package_version.edit.
function edit ( new_version_id in apm_package_versions.version_id%TYPE @@ -449,11 +232,9 @@ default 'f' ) return apm_package_versions.version_id%TYPE; --Versions can be enabled or disabled. Enabling a version instructs APM to +
Versions can be enabled or disabled. Enabling a version instructs APM to source the package's libraries on startup and to make the package -available to the OpenACS.
-+available to the OpenACS.procedure enable ( version_id in apm_package_versions.version_id%TYPE @@ -463,11 +244,9 @@ version_id in apm_package_versions.version_id%TYPE ); --Files associated with a version can be added and removed. The path is -relative to the package-root which is -acs-server-root/packages/package-key.
-+Files associated with a version can be added and removed. The path is +relative to the package-root which is +acs-server-root/packages/package-key.
-- Add a file to the indicated version. function add_file( file_id in apm_package_files.file_id%TYPE @@ -482,12 +261,10 @@ version_id in apm_package_versions.version_id%TYPE, path in apm_package_files.path%TYPE ); --Package versions need to indicate that they provide interfaces for other +
Package versions need to indicate that they provide interfaces for other software. An interface is an API that other packages can access and utilize. Interfaces are identified as a URI and a version name, that comply with the -specification of a version name for package URIs.
-+specification of a version name for package URIs.-- Add an interface provided by this version. function add_interface( @@ -509,11 +286,9 @@ version_id in apm_package_versions.version_id%TYPE ); --The primary use of interfaces is for other packages to specify required +
The primary use of interfaces is for other packages to specify required interfaces, known as dependencies. A package cannot be correctly installed -unless all of its dependencies have been satisfied.
-+unless all of its dependencies have been satisfied.-- Add a requirement for this version. A requirement is some interface that this -- version depends on. @@ -536,10 +311,8 @@ version_id in apm_package_versions.version_id%TYPE ); --As new versions of packages are created, it is necessary to compare their -version names. These two functions assist in that task.
-+As new versions of packages are created, it is necessary to compare their +version names. These two functions assist in that task.
-- Given a version_name (e.g. 3.2a), return -- something that can be lexicographically sorted. @@ -554,12 +327,9 @@ version_name_two in apm_package_versions.version_name%TYPE ) return integer; --Creating Instances of a Package
-Once a package is registered in the system, it is possible to create +
Creating Instances of a Package
Once a package is registered in the system, it is possible to create instances of it. Each instance can maintain its own content and -parameters.
-+parameters.create or replace package apm_application as @@ -582,12 +352,10 @@ ); end apm_application; --Just creating a package instance is not sufficient for it to be served +
Just creating a package instance is not sufficient for it to be served from the web server. A corresponding site node must be created for it. As an example, here is how the OpenACS API Documentation service -makes itself available on the OpenACS main site:
-+makes itself available on the OpenACS main site:declare api_doc_id integer; @@ -614,20 +382,16 @@ show errors --Specifying Configuration Parameters for each Instance
-A parameter is a setting that can be changed on a package instance basis. +
Specifying Configuration Parameters for each Instance
A parameter is a setting that can be changed on a package instance basis. Parameters are registered on each package_key, and the values are associated with each instance. Parameters can have default values and can be of type 'string' or 'number.' There is support with this API for setting a number of minimum and maximum values for each parameter, but for most instances, the minimum and maximum should be 1. It is useful to allow or require multiple values for packages that need to store multiple pieces of information under one parameter. Default values are automatically -set when instances are created, but can be changed for each instance.
-All of the functions below are in the APM PL/SQL -package.
-+set when instances are created, but can be changed for each instance.All of the functions below are in the APM PL/SQL +package.
-- Indicate to APM that a parameter is available to the system. function register_parameter ( @@ -673,10 +437,8 @@ default null ); --The following functions are used to associate values with parameters and -instances:
-+The following functions are used to associate values with parameters and +instances:
-- Return the value of this parameter for a specific package and parameter. function get_value ( @@ -702,218 +464,84 @@ attr_value in apm_parameter_values.attr_value%TYPE ); --
The central piece of the data model is the apm_package_types table where each package is registered. When a new application or service is installed on an OpenACS instance, a corresponding row in this table is inserted with information about the type of package, e.g. if the bboard package is installed on your OpenACS server, a row in apm_package_types will be created, noting that it's an -application package type.
-The apm_packages table is used to contain information about -the instances of packages currently created in the system. The +application package type.
The apm_packages table is used to contain information about +the instances of packages currently created in the system. The package_key column references the apm_package_types table to ensure that no package instance can be created for a type that does -not exist.
-The apm_package_versions table contains information specific +not exist.
The apm_package_versions table contains information specific to a particular version of a package. Several tables reference this one to -provide further information about the particular version:
--apm_package_owners +provide further information about the particular version:
apm_package_owners Stores information about the owners of a particular version of a package. -
-apm_package_files +
apm_package_files Stores information about the files that are part of a version. -
-apm_package_dependencies +
apm_package_dependencies Stores information about what interfaces the package provides and -requires.
Parameter information is maintained through two tables:
--apm_parameters +requires.
Parameter information is maintained through two tables:
apm_parameters This table contains the definition of each of the parameters for a package. -
-apm_parameter_values +
apm_parameter_values This table holds all of the values of parameters for specific package instances. -
A number of views are available for obtaining information about packages -registered in the APM.
--apm_package_version_info +
A number of views are available for obtaining information about packages +registered in the APM.
apm_package_version_info Provides information about all of the versions in the system with information available from the apm_package_types table. -
-apm_enabled_package_versions +
apm_enabled_package_versions A view (subset) of the above table with only enabled versions. -
-apm_file_info - Provides a public interface for querying file information.
The APM's user interface is part of the +
apm_file_info + Provides a public interface for querying file information.
The APM's user interface is part of the OpenACS Administration Service. The UI is the primary point of contact with APM by developers and administrators. It is part of OpenACS Administration, because only the site-wide administrator should be able to access it. Thus in order to develop a package, the developer must be granted -site-wide administration.
-APM has two parameters for configuring how it interacts with the UNIX +site-wide administration.
APM has two parameters for configuring how it interacts with the UNIX filesystem, accessible via the Site Map admin page. These parameters need not be changed under most circumstances, but may -need to be tweaked for Windows compatibility.
--GzipExecutableDirectory +need to be tweaked for Windows compatibility.
GzipExecutableDirectory This directory points to where the gunzip program can be found for uncompressing gzip archives. This is needed for the installation of .apm files which are simply gziped tarballs. Default is /usr/local/bin -
-InfoFilePermissionsMode +
InfoFilePermissionsMode This sets the default UNIX permissions used when creating files using the -APM. Default is 775.
APM has been in production since OpenACS 3.3, and as of version 4.0 offers a stable set of features. One major feature planned is integration with the OpenACS Package Repository for automatic dependency satisfaction. When a user tries to install a package that depends on other packages, the APM will contact the package repository, determine what packages depend on it, and offer the user a chance to download and install them all. This improvement offers value to -end users by facilitating the extension of their OpenACS systems.
-Architecturally, minor improvements to the data model and the +end users by facilitating the extension of their OpenACS systems.
Architecturally, minor improvements to the data model and the specification file are planned to increase modularity. The current implementation puts all package specification information in a single file. This approach has certain advantages, such as centralization, but splitting this information into several files allows for flexible extensions to the APM -architecture over time.
-APM packages currently lack provisions to verify security information. +architecture over time.
APM packages currently lack provisions to verify security information. There are plans to add MD5 time stamps and PGP signatures to packages to enable secure authentication of packages. These steps are necessary for APM to be usable as a scalable method to distribute packages on multiple -repositories worldwide.
-Another anticipated change is to split the APM UI into separate systems +repositories worldwide.
Another anticipated change is to split the APM UI into separate systems for authoring, maintaining, and installing packages. The current UI presents all of this functionality in one interface and it can be confusing from a -usability perspective.
-System creator: Bryan Quinn, Jon Salz, Michael Yoon, Lars Pind, Todd -Nightingale.
System owner: Bryan Quinn
Documentation author: Bryan Quinn, building from earlier versions by Jon -Salz, Michael Yoon, and Lars Pind.
Document Revision # | -Action Taken, Notes | -When? | -By Whom? | -
0.1 | -Creation | -9/25/2000 | -Bryan Quinn | -
0.8 | -Ready for QA | -9/29/2000 | -Bryan Quinn | -
0.9 | -Edited for ACS 4 Beta release | -10/02/2000 | -Kai Wu | -
1.0 | -Edited for OpenACS 4.5 Beta release | -03/02/2002 | -Roberto Mello | -
System creator: Bryan Quinn, Jon Salz, Michael Yoon, Lars Pind, Todd +Nightingale.
System owner: Bryan Quinn
Documentation author: Bryan Quinn, building from earlier versions by Jon +Salz, Michael Yoon, and Lars Pind.
The following is a requirements document for the OpenACS Package Manager +
The following is a requirements document for the OpenACS Package Manager (APM), version 4.0 (APM4). APM4 offers a superset of APM v3.3 functionality -with the following specific enhancements:
-A public procedural API. (v 3.3 only has web-based UI)
Support for dependency checking.
Support for compound packages (to support installation chaining).
Support for on-line parameter setting.
Support for sub-site level configuration (requires revised ad_parameter +with the following specific enhancements:
A public procedural API. (v 3.3 only has web-based UI)
Support for dependency checking.
Support for compound packages (to support installation chaining).
Support for on-line parameter setting.
Support for sub-site level configuration (requires revised ad_parameter and /admin pages at sub-site level; deprecation of site-wide parameter -file).
To differentiate these new requirements from the requirements of version +file).
To differentiate these new requirements from the requirements of version 3.3, all requirements new in v4 are prefaced with the number -4.
-We gratefully acknowledge the authors of APM 3 for their original design +4.
We gratefully acknowledge the authors of APM 3 for their original design documentation which suggested these features, as well as the influence of the design and open-source implementation of the Red Hat Package manager, the Debian packaging system, and PERL's CPAN in the development of the ideas -behind this document.
-A typical website will tend to offer its users a number of web-based +behind this document.
A typical website will tend to offer its users a number of web-based services or applications, e.g. a bulletin board, calendaring, classified ads, etc. A website may also have underlying subsystems, such as a permissions system, content management system, etc. For such applications and subsystem @@ -65,116 +24,41 @@ disturbance to the rest of the system. This allows site owners to steadily offer users new and improved services, and also allows programmers to quickly and easily distribute their OpenACS components in a standardized manner to other -OpenACS sites.
-In general terms, a package is a unit of software that serves a single +OpenACS sites.
In general terms, a package is a unit of software that serves a single well-defined purpose. The OpenACS Package Manager (APM) provides a mechanism for packaging, installing, and configuring OpenACS software in a consistent, -user-friendly, and subsite-aware manner.
-The OpenACS Package Manager (APM) consists of: -
--A standard format for APM packages including:
-Version numbering, independent of any other package and the OpenACS as a -whole
Specification of the package interface
Specification of dependencies on other packages (if any)
Attribution (who wrote it) and ownership (who maintains it)
-Web-based tools for package management:
-Obtaining packages from a remote distribution point
Installing packages, if and only if:
-All prerequisite packages are installed
No conflicts will be created by the installation
Configuring packages (obsoleting the monolithic OpenACS configuration -file)
Upgrading packages, without clobbering local modifications
Uninstalling unwanted packages
-A registry of installed packages, database-backed and +
A standard format for APM packages including:
Version numbering, independent of any other package and the OpenACS as a +whole
Specification of the package interface
Specification of dependencies on other packages (if any)
Attribution (who wrote it) and ownership (who maintains it)
Web-based tools for package management:
Obtaining packages from a remote distribution point
Installing packages, if and only if:
All prerequisite packages are installed
No conflicts will be created by the installation
Configuring packages (obsoleting the monolithic OpenACS configuration +file)
Upgrading packages, without clobbering local modifications
Uninstalling unwanted packages
A registry of installed packages, database-backed and integrated with file system-based version control -
-Web-based tools for package development:
-Creating new packages locally
Releasing new versions of locally-created packages
Uploading packages to a global package repository on the web
Use of these tools should be safe, i.e. installing or removing a package -should never break an OpenACS installation
-Web-based tools for package configuration:
-The ability to change package parameter values on-line through a simple -web interface.
A new ad_parameter which does not require a monolithic site-wide -parameter's file or server restarts for changes to take effect.
The ability to manage multiple package instances at the sub-site -level.
+
Web-based tools for package development:
Creating new packages locally
Releasing new versions of locally-created packages
Uploading packages to a global package repository on the web
Use of these tools should be safe, i.e. installing or removing a package +should never break an OpenACS installation
Web-based tools for package configuration:
The ability to change package parameter values on-line through a simple +web interface.
A new ad_parameter which does not require a monolithic site-wide +parameter's file or server restarts for changes to take effect.
The ability to manage multiple package instances at the sub-site +level.
The APM is intended for the following classes of users, which may or may not -overlap:
--Developers (referred to as 'the developer') use +overlap:
Developers (referred to as 'the developer') use the APM to create a software package for distribution and use the procedural -API for direct control of the APM system.
-Site-wide administrators (referred to as 'the +API for direct control of the APM system.
Site-wide administrators (referred to as 'the administrator') use the APM to install packages for their OpenACS instance, -and optionally make them available to sub-sites.
-Sub-site administrators (referred to as 'the +and optionally make them available to sub-sites.
Sub-site administrators (referred to as 'the sub-admin') use an administration interface to configure and enable -packages for their sub-site.
Initial Package Development
--David Developer writes a piece of software used to do +packages for their sub-site.
Initial Package Development
David Developer writes a piece of software used to do knowledge management (km) for the OpenACS. He distributes his data model, procedure code, UI pages, and his documentation according to the APM specification. He splits the documentation and the code into sub-packages, and creates a KM installation-chain to install both with the APM developer -UI. Noting that his software was built with Patricia -Programmer's Super Widget toolkit, he specifies that as a +UI. Noting that his software was built with Patricia +Programmer's Super Widget toolkit, he specifies that as a dependency. Moreover, since this package is capable of being used at the sub-site level, David configures this option in the package. When the package development is complete, David uses the APM developer UI to construct a distribution file. He assigns it a version number, 1.0, and makes the package -available for download at the OpenACS package repository.
-Initial Package Installation
--Annie Admin learns of David's KM system by browsing +available for download at the OpenACS package repository.
Initial Package Installation
Annie Admin learns of David's KM system by browsing the OpenACS package repository. Annie Admin uses the APM administrator UI on her system. She selects to install a package from a URL and types the URL displayed on the system. The APM automatically downloads the package. The @@ -185,685 +69,230 @@ toolkit. Annie confirms this option. After successfully installing Jim's toolkit, Annie proceeds to install David's KM system. The data model is loaded and all of the files necessary for the software are installed. Because -installation was successful, the package is available for use.
-Since the package is available for use, its initialization routines are +installation was successful, the package is available for use.
Since the package is available for use, its initialization routines are set to run automatically on server startup. Annie is warned that since there are initialization routines, she must restart the server for the package to -be ready for use. Annie restarts the server.
-Initial Subsite Use of Package
-Annie Admin decides to make the KM module available only to a particular +be ready for use. Annie restarts the server.
Initial Subsite Use of Package
Annie Admin decides to make the KM module available only to a particular sub-site type on her OpenACS system, and not others. She specifies this option -using the Sub-site type UI (not part of APM).
-Annie Admin notifies Sally SubAdmin by e-mail that a new +using the Sub-site type UI (not part of APM).
Annie Admin notifies Sally SubAdmin by e-mail that a new package is now available for use. Sally goes to her sub-site /admin page and sees that a new entry, KM, is available. Sally clicks on it and finds links to the installed KM documentation and to the web based configuration utility. Then, Sally configures the package using an automatically generated web interface and enables KM for use on her sub-site. After some initial use of the package, Sally decides to change some parameters using the SubAdmin UI. -These changes take effect immediately, without any server restarts.
-Upgrade Process
-Sally SubAdmin finds a bug in the KM system and sends a report to David +These changes take effect immediately, without any server restarts.
Upgrade Process
Sally SubAdmin finds a bug in the KM system and sends a report to David Developer. David reads the bug report and verifies that the bugs are present in the current version. Because the bugs are present in the shared procedure file, David assigns a watch to the file. David makes the necessary modifications to the source code and saves the file. Because a watch was assigned to the file, the APM automatically reloads the updated code. David tests the program and confirms that the bug is fixed. He increments the minor version number and makes km v 1.1 available for download at the -repository.
-Sally SubAdmin asks Annie Administrator to upgrade the package using the +repository.
Sally SubAdmin asks Annie Administrator to upgrade the package using the APM UI. This upgrade supersedes the old version of KM at the site-wide level. Once Annie upgrades the package, the new version starts working immediately -in Sally's sub-site.
-Procedural API
--Danielle Developer wants her software to perform +in Sally's sub-site.
Procedural API
Danielle Developer wants her software to perform different actions depending on what version of another package is installed. She uses the APM procedural API to check if KM version 1.0 is installed or version 1.1. Based on the results of this procedural call, the software -exhibits different behavior.
--4.500.0 Package Identification -(All of these items are entered by the developer using the developer UI.)
--4.500.1 A human readable package key that is guaranteed +exhibits different behavior.
4.500.0 Package Identification +(All of these items are entered by the developer using the developer UI.)
4.500.1 A human readable package key that is guaranteed to be unique to the local OpenACS site must be maintained by the APM. For -example, "apm."
--4.500.5 A package id (primary key) that is guaranteed to +example, "apm."
4.500.5 A package id (primary key) that is guaranteed to be unique to the local site must be maintained by the APM. For example, -"25."
--4.500.10 A package URL that is guaranteed to be unique +"25."
4.500.10 A package URL that is guaranteed to be unique across all sites must be maintained by the APM. The package URL should point to a server that allows download of the latest version of the package. For example, "http://openacs.org/software." -
--4.505.0 Version Identification - (All of these items are entered by the developer using the developer UI.)
--4.505.1 A version id (primary key) that is guaranteed to -be unique to the local site must be maintained by the APM.
--4.505.5 A version URL that is guaranteed to be unique +
4.505.0 Version Identification + (All of these items are entered by the developer using the developer UI.)
4.505.1 A version id (primary key) that is guaranteed to +be unique to the local site must be maintained by the APM.
4.505.5 A version URL that is guaranteed to be unique across all sites must be maintained by the APM. The version URL should point to a server that allows download of a specific version of the package. -
-The API for APM v3 is explicitly a private API. However, it would be useful to obtain information from the APM through a procedural API. Implementing the API specified below is quite easy given that there are pages -that already do all of the below in raw SQL.
--4.400.0 Packages Status Predicates
--4.400.1 Given defining information such as a package URL, +that already do all of the below in raw SQL.
4.400.0 Packages Status Predicates
4.400.1 Given defining information such as a package URL, the APM API can return the status of the package on the local OpenACS -instance.
--4.405.0 Package Information Procedures
--4.405.1 The APM API can return information for any +instance.
4.405.0 Package Information Procedures
4.405.1 The APM API can return information for any locally installed packages, including the version number, paths and files, -and package key.
--4.410.0 Sub-site Procedures
--4.410.1 After a package has been installed at the +and package key.
4.410.0 Sub-site Procedures
4.410.1 After a package has been installed at the site-wide level, the system API will provide means to check for package -presence, creation, enabling, disabling, and destruction on a subsite.
--4.415.0 Parameter Values (replaces ad_parameter)
--4.415.1 The system API shall allow subsite parameters for +presence, creation, enabling, disabling, and destruction on a subsite.
4.415.0 Parameter Values (replaces ad_parameter)
4.415.1 The system API shall allow subsite parameters for an installed package to be set by either site-wide administrators or sub-site admins. The subsite parameter can be set to be non-persistent (but default is to survive server restarts). The subsite parameter can also be set to only -take effect after a server restart (default is immediate).
--4.415.5 Parameters for a given subsite and package can be -returned by the system API.
-Provisions will be made to assure that packages are securely -identified.
--4.600.1 Each package will have a PGP signature and there +identified.
4.600.1 Each package will have a PGP signature and there will be MD5 time stamps for each file within the package. -
-4.600.5 The APM will provide a facility to validate both -the PGP signature and MD5 stamps information before a package install.
The user interface is a set of HTML pages that are used to drive the underlying API. It is restricted to site-wide administrators because the -actions taken here can dramatically affect the state of the running OpenACS.
-The intent of the developer's interface is to enable the developer to +actions taken here can dramatically affect the state of the running OpenACS.
The intent of the developer's interface is to enable the developer to construct and maintain APM packages. It will be possible to disable the developer's interface for production sites to help reduce the chance of site failure; much of the functionality here can have cascading effects -throughout the OpenACS and should not be used on a production site.
-10.0 Define a package.
-The developer must be able to create a new package by specifying some +throughout the OpenACS and should not be used on a production site.
10.0 Define a package.
The developer must be able to create a new package by specifying some identifying information for the package. This includes a package name, a -package key, version information, owner information, and a canonical URL.
--10.1 The APM must maintain the state of all locally -generated packages.
--10.50 If the developer fails to provide the required -information, the package cannot be created.
--10.55 All of the package information should be editable -after creation, except for the package key.
--4.10.60 The package creator must specify whether the +package key, version information, owner information, and a canonical URL.
10.1 The APM must maintain the state of all locally +generated packages.
10.50 If the developer fails to provide the required +information, the package cannot be created.
10.55 All of the package information should be editable +after creation, except for the package key.
4.10.60 The package creator must specify whether the package is capable of being used in sub-sites, or if only a single, global -instance of the package is permitted.
--4.10.65 If the developer fails to provide unique +instance of the package is permitted.
4.10.65 If the developer fails to provide unique information for unique fields specified in the data model requirements, the -package cannot be created.
--20.0 Add files to a package
--20.1 The developer must be able to add files to the +package cannot be created.
20.0 Add files to a package
20.1 The developer must be able to add files to the package. This is done by copying the files into the package directory in the host OS's file system. Files can be added at any point after package -creation.
--20.3 Once a package has been versioned and distributed, +creation.
20.3 Once a package has been versioned and distributed, no new files should be added to the package without incrementing the version -number.
--20.5 The APM's UI should facilitate the process of +number.
20.5 The APM's UI should facilitate the process of adding new files, by scanning the file system for new files automatically, -and allowing the developer to confirm adding them.
--20.10 The developer cannot add files to a given package -via the UI that do not exist in the file system already.
--20.15 Package file structure must follow a specified +and allowing the developer to confirm adding them.
20.10 The developer cannot add files to a given package +via the UI that do not exist in the file system already.
20.15 Package file structure must follow a specified convention. Please see the design -document for what we do currently.
-30.0 Remove files from a package
-The developer must be able to remove files from a package. This can be -done in two ways.
--30.1 Access the APM UI, browse the file list, and remove -files.
--30.1.1If a file is removed from the package list, but not -from the file system, an error should be generated at package load time.
--30.5 Remove the file from file system.
--30.5.1 The APM UI should take note of the fact that the +document for what we do currently.
30.0 Remove files from a package
The developer must be able to remove files from a package. This can be +done in two ways.
30.1 Access the APM UI, browse the file list, and remove +files.
30.1.1If a file is removed from the package list, but not +from the file system, an error should be generated at package load time.
30.5 Remove the file from file system.
30.5.1 The APM UI should take note of the fact that the file is gone and offer the developer an option to confirm the file's deletion. -
--40.0 Modify files in a package.
--40.1 The developer should be able to modify files in the -file system. The APM UI should not interfere with this.
--40.5 However, if the developer modifies files containing -procedural definitions, APM UI should allow a means to watch +
40.0 Modify files in a package.
40.1 The developer should be able to modify files in the +file system. The APM UI should not interfere with this.
40.5 However, if the developer modifies files containing +procedural definitions, APM UI should allow a means to watch those files and automatically reload them if changed. See requirement 50.0 -for more detail.
--40.10 Also, although a change in files implies that the +for more detail.
40.10 Also, although a change in files implies that the package distribution file is out of date, it is the developer's -responsibility to update it.
--4.45.0 Manage Package Dependency Information.
--4.45.1 The developer should be able to specify which -interfaces the package requires.
--4.45.5 The developer should be able to specify which -interfaces the package provides.
--4.45.10 Circular dependencies are not allowed.
--50.0 Watch a file
--4.50.1 The developer should be able to assign a watch to -any Tcl procedure file, whether in /packages or /tcl.
--50.5 If a watched file is locally modified, then it will +responsibility to update it.
4.45.0 Manage Package Dependency Information.
4.45.1 The developer should be able to specify which +interfaces the package requires.
4.45.5 The developer should be able to specify which +interfaces the package provides.
4.45.10 Circular dependencies are not allowed.
50.0 Watch a file
4.50.1 The developer should be able to assign a watch to +any Tcl procedure file, whether in /packages or /tcl.
50.5 If a watched file is locally modified, then it will be automatically reloaded, thus allowing for any changes made to take affect -immediately.
--4.50.10 The setting of a watch should be persistent +immediately.
4.50.10 The setting of a watch should be persistent across server restarts. -
--60.0 Display an XML package specification
--60.1 The developer should be able to view the XML package +
60.0 Display an XML package specification
60.1 The developer should be able to view the XML package specification that encodes all package information. -
--70.0 Write an XML package specification to the file -system
--70.1 The developer should be able to write an up-to-date -XML specification to disk.
--70.5 The developer should be able to request the current -XML specification for all installed, locally generated packages.
--130.0 Distribution file generation
--130.1 The developer should be able to generate a .APM -distribution file for the package with just one click.
--130.5 Generating a distribution file implies doing an +
70.0 Write an XML package specification to the file +system
70.1 The developer should be able to write an up-to-date +XML specification to disk.
70.5 The developer should be able to request the current +XML specification for all installed, locally generated packages.
130.0 Distribution file generation
130.1 The developer should be able to generate a .APM +distribution file for the package with just one click.
130.5 Generating a distribution file implies doing an "up-to-date" check on all of the files. If any of the files have changed since package installation, then a new version of the package is created. -
--140.0 Access CVS information
--140.1 The developer should be able to determine the CVS +
140.0 Access CVS information
140.1 The developer should be able to determine the CVS status of a package, or all packages, with a single click. -
--4.200.0 Compound Package Construction
--4.200.1 The developer can include .APM packages +
4.200.0 Compound Package Construction
4.200.1 The developer can include .APM packages (sub-packages) within a package (the compound package) like any other -file.
--4.200.5 The recommended usage for this feature is to +file.
4.200.5 The recommended usage for this feature is to allow for separation of optional and required components from the installation as well as better organization of files once installed. For example, all documentation for the community-core can be packages as community-core-doc.apm. It is legal to include sub-packages with dependencies that are not satisfied by the packages in the compound package, but this is discouraged. In such a case, the sub-package should really be a -separate package that is required by the compound package.
--4.200.10 If a sub-package is required for the +separate package that is required by the compound package.
4.200.10 If a sub-package is required for the installation of the compound package, the compound package should have a -registered dependency on the sub-package.
-The requirement of the administrator's interface is to enable the administrator to install, enable, upgrade, disable, deinstall, and delete -packages.
--80.0 Package Enable/Disable
--4.80.1 The administrator should be able mark an installed +packages.
80.0 Package Enable/Disable
4.80.1 The administrator should be able mark an installed package as enabled. This means that the package is activated and its functionality is delivered through the Request Processor. As of OpenACS 4, this -is done through the sub-site system.
--4.80.5 Moreover, the administrator must be able to +is done through the sub-site system.
4.80.5 Moreover, the administrator must be able to disable a package, thereby removing the functionality provided to a sub-site. As of OpenACS 4, this is done through the sub-site system. -
--90.0 Package Install
--90.1 The administrator must be able to install new -packages either from locally maintained .APM files or from URLs.
--90.5 In the case of an URL, the APM transparently +
90.0 Package Install
90.1 The administrator must be able to install new +packages either from locally maintained .APM files or from URLs.
90.5 In the case of an URL, the APM transparently downloads the APM file off the web, proceeds with a file based installation, -and then optionally removes the .APM file just downloaded.
--90.10.1 If .APM files are present in a package, then it -is considered a compound package (use 4.210.0).
--90.15.0 Installation requires these steps:
--90.15.1The package dependencies are scanned. If some +and then optionally removes the .APM file just downloaded.
90.10.1 If .APM files are present in a package, then it +is considered a compound package (use 4.210.0).
90.15.0 Installation requires these steps:
90.15.1The package dependencies are scanned. If some dependencies are not present, the system warns the administrator that -installation cannot proceed until those packages are installed.
-90.15.2 Assuming all dependencies are present, APM -extracts the contents of the APM file into the /packages directory.
-90.15.3 The administrator is offered the option of -importing directly into CVS.
-90.15.4 The administrator is given a list of data model -scripts found in the package and can select which ones to be executed.
-90.15.5 If no errors are recorded during this process, -the package is enabled.
-4.210.0 Compound package Install
--4.210.1 If .APM files are present in a package, then it -is considered a compound package.
--4.210.5.0 Installation of a compound package proceeds -according to the following sequence:
--4.210.5.1 Identify the set of all sub-packages within -the compound package by scanning for all files with .APM.
-4.210.5.2 Identify which sub-packages are required by +installation cannot proceed until those packages are installed.
90.15.2 Assuming all dependencies are present, APM +extracts the contents of the APM file into the /packages directory.
90.15.3 The administrator is offered the option of +importing directly into CVS.
90.15.4 The administrator is given a list of data model +scripts found in the package and can select which ones to be executed.
90.15.5 If no errors are recorded during this process, +the package is enabled.
4.210.0 Compound package Install
4.210.1 If .APM files are present in a package, then it +is considered a compound package.
4.210.5.0 Installation of a compound package proceeds +according to the following sequence:
4.210.5.1 Identify the set of all sub-packages within +the compound package by scanning for all files with .APM.
4.210.5.2 Identify which sub-packages are required by checking the dependencies of the compound package. If there dependencies not satisfied by the current system or the packages included with the compound package, halt installation and inform user to install these packages -first.
-4.210.5.3 Present Administrator with the ability to +first.
4.210.5.3 Present Administrator with the ability to choose which sub-packages to install. Required sub-packages must be -installed.
-4.210.5.4 Proceed with the installation of each +installed.
4.210.5.4 Proceed with the installation of each sub-package, starting with required packages. If the sub-package is already installed, then do nothing. Else, If the sub-package is a normal package, -proceed according to 90.15.0, otherwise if it is a compound -package, proceed according to 4.210.5.0.
-4.210.5.5 If all required sub-packages are installed, +proceed according to 90.15.0, otherwise if it is a compound +package, proceed according to 4.210.5.0.
4.210.5.5 If all required sub-packages are installed, proceed to install non-required sub-packages. If there was a failure during the installation of a required sub-package, then the installation of the -compound package is also a failure.
-4.210.5.6 Any attempt to install a compound package in +compound package is also a failure.
4.210.5.6 Any attempt to install a compound package in the future involves a choice presented to the admin of installing any -uninstalled sub-packages.
4.220.0 Recovering from failed package installation
--4.220.1 If any error is generated during package +uninstalled sub-packages.
4.220.0 Recovering from failed package installation
4.220.1 If any error is generated during package installation, the package is not considered installed. To recover from this -failure, the package should be selected for installation again.
--100.0 Version Upgrade
--100.1 The administrator can upgrade to a new version of a -package. This entails
--100.1.1 Running any necessary and included upgrade -scripts.
-100.1.5 Replacing any old files with new versions.
-100.1.10 Marking the old version of the package as -'superseded' and disabling it.
-100.1.15 Assuming no errors from above, the new package -is enabled.
-110.0 Package Deinstall
--110.1 The administrator must be able to deinstall a -package that has already been installed. Deinstallation entails:
--110.1.1 Running any data model scripts necessary to drop -the package.
-110.1.5 Moving all of the files into a separate location -in the file system from the installed packages.
-4.110.1.10 If the package is a compound package, then +failure, the package should be selected for installation again.
100.0 Version Upgrade
100.1 The administrator can upgrade to a new version of a +package. This entails
100.1.1 Running any necessary and included upgrade +scripts.
100.1.5 Replacing any old files with new versions.
100.1.10 Marking the old version of the package as +'superseded' and disabling it.
100.1.15 Assuming no errors from above, the new package +is enabled.
110.0 Package Deinstall
110.1 The administrator must be able to deinstall a +package that has already been installed. Deinstallation entails:
110.1.1 Running any data model scripts necessary to drop +the package.
110.1.5 Moving all of the files into a separate location +in the file system from the installed packages.
4.110.1.10 If the package is a compound package, then the administrator must confirm removing all sub-packages. Optionally, some -sub-packages can be kept.
-110.5 Deinstalled packages can be re-installed at a later -date.
--4.110.10 If deinstalling a package or any of its +sub-packages can be kept.
110.5 Deinstalled packages can be re-installed at a later +date.
4.110.10 If deinstalling a package or any of its sub-packages breaks a dependency, then deinstallation cannot proceed until -the package registering the dependency is removed.
--120.0 Package Deletion
--120.1 The administrator should be able to completely +the package registering the dependency is removed.
120.0 Package Deletion
120.1 The administrator should be able to completely erase all records of the package. This involves removing all instances of the -package, all related database tables and content.
--120.5 This option can only be used if all package +package, all related database tables and content.
120.5 This option can only be used if all package instances are deleted or marked as disabled. This is purposefully cumbersome because deleting all instances of a package can have far-sweeping -consequences throughout a site and should almost never be done.
--150.0 Scan for new or modified packages
--150.1 The administrator should be able to scan the file -system for any changes made in any of the installed package files.
--150.5 The administrator should be able to scan the file +consequences throughout a site and should almost never be done.
150.0 Scan for new or modified packages
150.1 The administrator should be able to scan the file +system for any changes made in any of the installed package files.
150.5 The administrator should be able to scan the file system for any newly installed packages. -
-If the developer is in charge of creating packages and the administrator for installing them, then the sub-site administrator is responsible for configuring and enabling packages. In order for a package to be available for a sub-site it must be associated with the sub-site's type specification. This interface is part of the sub-site /admin interface. -
--4.300 Creating a package instance.
--4.300.1 From the sub-site /admin interface, there should +
4.300 Creating a package instance.
4.300.1 From the sub-site /admin interface, there should be an option to view all packages available in the system as well as an -option to add a package to the subsite.
--4.300.5 From the "add" option, the sub-admin +option to add a package to the subsite.
4.300.5 From the "add" option, the sub-admin can select from a list of packages registered as available in the sub-site -type to which the sub-site belongs.
--4.300.19 Once a package instance is added, it is -available on the list of the subsite's available packages.
--4.305 Configuring a package instance.
--4.305.1 An automatic web interface that lists all -parameters with current values must be available.
--4.305.5 Changing the values for the parameters is -accomplished simply by submitting an HTML form.
--4.310 Enabling a package instance.
--4.310.1 The sub-admin should be able to enable a package +type to which the sub-site belongs.
4.300.19 Once a package instance is added, it is +available on the list of the subsite's available packages.
4.305 Configuring a package instance.
4.305.1 An automatic web interface that lists all +parameters with current values must be available.
4.305.5 Changing the values for the parameters is +accomplished simply by submitting an HTML form.
4.310 Enabling a package instance.
4.310.1 The sub-admin should be able to enable a package with a single click. Enabling a package means that the OpenACS will serve its URLs properly. -
--4.315 Disabling a package instance.
--4.315.1 The sub-admin should be able to disable a package +
4.315 Disabling a package instance.
4.315.1 The sub-admin should be able to disable a package with a single click. Disabling a package means that the OpenACS will no longer -serve those URLs.
--4.320 Deleting a package instance.
--4.320.1 Deleting a package instance involves deleting not +serve those URLs.
4.320 Deleting a package instance.
4.320.1 Deleting a package instance involves deleting not only the package instance, but any and all content associated with it. It is questionable whether this option should even be available due to its drastic consequences. Reviewer comments appreciated. -
-Despite the fact that requirements are meant to be design/implementation neutral, the following thoughts were in our head when specifying these requirements. You must be familiar with the new object design for this to be -comprehensible.
-When a package is installed system-wide, a corresponding acs_object_type +comprehensible.
When a package is installed system-wide, a corresponding acs_object_type is created for it. All parameters registered for the package are registered -for that acs_object_type.
-When a package instance is created, it is an acs_object. Its parameters +for that acs_object_type.
When a package instance is created, it is an acs_object. Its parameters are set using the acs_attribute_values table. The automatic web interface for setting package parameters should be one and the same with the interface for setting acs object attribute values. Consequently, the implementation of -these features should be quite straightforward.
-Document Revision # | -Action Taken, Notes | -When? | -By Whom? | -
0.1 | -Creation | -8/10/2000 | -Bryan Quinn, Todd Nightingale | -
� | -Reviewed | -8/11/2000 | -John Prevost, Mark Thomas, and Pete Su | -
0.2 | -Revised and updated | -8/12/2000 | -Bryan Quinn | -
0.3 | -Reviewed, revised, and updated - conforms to requirements template. | -8/18/2000 | -Kai Wu | -
0.4 | -Minor edits before ACS 4 Beta. | -9/30/2000 | -Kai Wu | -
Document Revision # | Action Taken, Notes | When? | By Whom? |
0.1 | Creation | 8/10/2000 | Bryan Quinn, Todd Nightingale |
� | Reviewed | 8/11/2000 | John Prevost, Mark Thomas, and Pete Su |
0.2 | Revised and updated | 8/12/2000 | Bryan Quinn |
0.3 | Reviewed, revised, and updated - conforms to requirements template. | 8/18/2000 | Kai Wu |
0.4 | Minor edits before ACS 4 Beta. | 9/30/2000 | Kai Wu |
Tcl code: /tcl/0-acs-init.tcl and /packages/acs-kernel/bootstrap.tcl
This document describes the startup (bootstrapping) process for an AOLserver +
Tcl code: /tcl/0-acs-init.tcl and /packages/acs-kernel/bootstrap.tcl
This document describes the startup (bootstrapping) process for an AOLserver running OpenACS. -
-+
Before OpenACS 3.3, the OpenACS startup process was extremely simple: after AOLserver performed its internal initialization (reading the configuration file, loading shared libraries and module code, etc.) it scanned through the Tcl -library directory (generally /web/yourservername/tcl), +library directory (generally /web/yourservername/tcl), sourcing each file in sequence. -
-While this overall structure for initialization is still intact, package +
While this overall structure for initialization is still intact, package management has thrown a wrench into the works - there are a few extra things -to do during initialization, most notably:
-Examine the OpenACS file tree for files that should not be present in OpenACS +to do during initialization, most notably:
Examine the OpenACS file tree for files that should not be present in OpenACS (i.e., that were once part of the OpenACS distribution but have since been -removed).
Scan the /packages directory for new packages.
Initialize enabled packages by sourcing their *-procs.tcl -and *-init.tcl files.
+removed).
Scan the /packages directory for new packages.
Initialize enabled packages by sourcing their *-procs.tcl +and *-init.tcl files.
This document examines in detail each of the steps involved in AOLserver/OpenACS startup. -
-As soon as the nsd daemon is executed by the init process (or otherwise), AOLserver reads its configuration file and chroots itself if necessary. It then loads shared libraries indicated in the .ini file (e.g., the Oracle driver and nssock), and sources Tcl module files (generally in /home/aol30/modules/tcl). This step is, and has always been, the same for all AOLservers, regardless of whether they are running OpenACS. -
-Next AOLserver sources, in lexicographical order, each file in the +
Next AOLserver sources, in lexicographical order, each file in the /tcl directory. The first such file is 0-acs-init.tcl, which doesn't do much directly except to -determine the OpenACS path root (e.g., /web/yourservername) +determine the OpenACS path root (e.g., /web/yourservername) by trimming the final component from the path to the Tcl library directory -(/web/yourservername/tcl). But +(/web/yourservername/tcl). But 0-acs-init.tcl's has an important function, namely sourcing -/packages/acs-core/bootstrap.tcl, which does the following:
--Initialize some NSVs used by the core. These NSVs are +/packages/acs-core/bootstrap.tcl, which does the following:
Initialize some NSVs used by the core. These NSVs are documented in /packages/acs-core/apm-procs.tcl - no need to worry about them unless you're an OpenACS core hacker. -
-Verify the deletion of obsolete OpenACS files. The +
Verify the deletion of obsolete OpenACS files. The /tcl directory has evolved quite a bit over the months and years, and a few files have come and gone. The /www/doc/removed-files.txt file contains a list of files which -must be deleted from the AOLserver installation, at the risk of +must be deleted from the AOLserver installation, at the risk of causing weird conflicts, e.g., having several security filters registered. bootstrap.tcl scans through this list, logging error messages to the log if any of these files exist. -
-Source *-procs.tcl files in the OpenACS core. +
Source *-procs.tcl files in the OpenACS core. We source each file matching the *-procs.tcl glob in the /packages/acs-kernel directory, in lexicographical order. These procedure are needed to perform any of the following steps. -
-Ensure that the database is available by grabbing and +
Ensure that the database is available by grabbing and releasing a handle. If we can't obtain a handle, we terminate initialization (since OpenACS couldn't possibly start up the server without access to the database). -
-Register any new packages in the /packages -directory. In each directory inside /packages, we look +
Register any new packages in the /packages +directory. In each directory inside /packages, we look for a .info file; if we find a package that hasn't yet been registered with the package manager (i.e., it's been copied there manually), we insert information about it into the database. (The first time -OpenACS starts up, no packages will have been registered in the database +OpenACS starts up, no packages will have been registered in the database yet, so this step will registers every single package in the /packages directory.) Note that packages discovered here are initially disabled; they must be manually enabled in the package manager before they can be used. -
-Ensure that the acs-kernel package is -enabled. If the OpenACS core isn't initialized, the server +
Ensure that the acs-kernel package is +enabled. If the OpenACS core isn't initialized, the server couldn't possibly be operational, so if there's no enabled version of the OpenACS core we simply mark the latest installed one as enabled. -
-Load *-procs.tcl files for enabled -packages, activating their APIs. +
Load *-procs.tcl files for enabled +packages, activating their APIs. -
-Load *-init.tcl files for enabled packages, +
Load *-init.tcl files for enabled packages, giving packages a chance to register filters and procedures, initialize data structures, etc. -
-Verify that the core has been properly initialized by +
Verify that the core has been properly initialized by checking for the existence of an NSV created by the request processor initialization code. If it's not present, the server won't be -operational, so we log an error.
+operational, so we log an error.
At this point, bootstrap.tcl is done executing. AOLserver proceeds to source the remaining files in the /tcl directory (i.e., unpackaged libraries) and begins listening for connections. -
--Vinod Kurup put +
Vinod Kurup put together the January 2002 version of this guide from many sources of - information.
-+ information.
+
Acknowledgments for versions of the above documents go (in no particular order) to Bryan Quinn, Adam Farkas, Brian Stein, Doug Hoffman, Ravi Jasuja, Hiro Iwashima, Ryan Lee, Jonathan Goler, Audrey @@ -55,41 +26,15 @@ Richard Li, Jon Griffin, Roberto Mello, Gilbert Wong, Don Baccus, Ben Adida, Michael Cleverly, Janne Blonqvist, Jonathan Ellis, Janine Sisk, Jade Rubick, Chris Hardy, Jonathan Marsden, Vinod Kurup, Charles Hall, - Tom Jackson and Karl Lehenbauer.
-+ Tom Jackson and Karl Lehenbauer.
Several people have helped with this document, including Torben Brosten, Don Baccus, Roberto Mello, Talli Somekh, Dave Bauer, Jim - Lynch, Jon Griffin and Daryl Biberdorf. -
-- All questions and comments regarding - this guide should be sent to vinod@kurup.com or on the OpenACS bboards. -
-Tcl procedures: /packages/acs-kernel/10-database-procs.tcl
Tcl initialization: /packages/acs-kernel/database-init.tcl
+
Tcl procedures: /packages/acs-kernel/10-database-procs.tcl
Tcl initialization: /packages/acs-kernel/database-init.tcl
One of OpenACS's great strengths is that code written for it is very close to the database. It is very easy to interact with the database from anywhere within OpenACS. Our goal is to develop a coherent API for database access which makes this even easier. -
-There were four significant problems with the way OpenACS previously used the -database (i.e., directly through the ns_db interface):
--Handle management. We required code to pass database +
There were four significant problems with the way OpenACS previously used the +database (i.e., directly through the ns_db interface):
Handle management. We required code to pass database handles around, and for routines which needed to perform database access but didn't receive a database handle as input, it was difficult to know from which of the three "magic pools" (main, subquery, and log) to allocate a new handle. -
-Nested transactions. In our Oracle driver, begin +
Nested transactions. In our Oracle driver, begin transaction really means "turn auto-commit mode off" and end transaction means "commit the current transaction and turn auto-commit mode on." Thus if transactional code needed to call a routine which needed to operate transactionally, the semantics were -non-obvious. Consider:
-+non-obvious. Consider:proc foo { db args } { db_transaction { @@ -74,8 +37,7 @@ db_dml unused "insert into greeble(bork) values(50)" } --+
This would insert greeble #33 and do all the stuff in foo transactionally, but the end transaction in foo would actually cause a commit, and greeble #50 would later be inserted in @@ -84,82 +46,55 @@ already have been committed!. This is not a good thing. -
--Unorthodox use of variables. The standard mechanism for +
Unorthodox use of variables. The standard mechanism for mapping column values into variables involved the use of the set_variables_after_query routine, which relies on an uplevel variable named selection (likewise for set_variables_after_subquery and subselection). -
-Hard-coded reliance on Oracle. It's difficult to +
Hard-coded reliance on Oracle. It's difficult to write code supporting various different databases (dynamically using the appropriate dialect based on the type of database being used, e.g., using DECODE on Oracle and CASE ... WHEN on -Postgres).
+Postgres).
The Database Access API addresses the first three problems by: -
-making use of database handles transparent
wrapping common database operations (including transaction management) in -Tcl control structures (this is, after all, what Tcl is good at!)
+
making use of database handles transparent
wrapping common database operations (including transaction management) in +Tcl control structures (this is, after all, what Tcl is good at!)
It lays the groundwork for addressing the fourth problem by assigning each SQL statement a logical name. In a future version of the OpenACS Core, this API will translate logical statement names into actual SQL, based on the type of database in use. (To smooth the learning curve, we provide a facility for writing SQL inline for a "default SQL dialect", which we assume to be Oracle for now.) -
-To be clear, SQL abstraction is not fully implemented in OpenACS +
To be clear, SQL abstraction is not fully implemented in OpenACS 3.3.1. The statement names supplied to each call are not used by the API at all. The API's design for SQL abstraction is in fact incomplete; -unresolved issues include:
-how to add WHERE clause criteria dynamically
how to build a dynamic ORDER BY clause (Ben Adida has a -proposed solution for this)
how to define a statement's formal interface (i.e., what bind +unresolved issues include:
how to add WHERE clause criteria dynamically
how to build a dynamic ORDER BY clause (Ben Adida has a +proposed solution for this)
how to define a statement's formal interface (i.e., what bind variables it expects, what columns its SELECT clause must contain if it's a query) without actually implementing the statement in a -specific SQL dialect
+specific SQL dialect
So why is the incremental change of adding statement naming to the API worth the effort? It is worth the effort because we know that giving each SQL statement a logical name will be required by the complete SQL abstraction design. Therefore, we know that the effort will not be wasted, and taking advantage of the new support for bind variables will already require code that uses 3.3.0 version of the API to be updated. -
-set_variables_after_query is gone! (Well, it's still there, but you'll never need to use it.) The new API routines set local variables automatically. For instance: -
-+db_1row select_names "select first_names, last_name from users where user_id = [ad_get_user_id]" doc_body_append "Hello, $first_names $last_name!" --+
Like ns_db 1row, this will bomb if the query doesn't return any rows (no such user exists). If this isn't what you want, you can write: -
-+if { [db_0or1row select_names "select first_names, last_name from users where user_id = [ad_get_user_id]"] } { doc_body_append "Hello, $first_names $last_name!" @@ -168,44 +103,34 @@ doc_body_append "There's no such user!" } --+
Selecting a bunch of rows is a lot prettier now: -
-+db_foreach select_names "select first_names, last_name from users" { doc_body_append "Say hi to $first_names $last_name for me!<br>" } --+
That's right, db_foreach is now like ns_db select plus a while loop plus set_variables_after_query plus an if statement (containing code to be executed if no rows are returned). -
-+db_foreach select_names "select first_names, last_name from users where last_name like 'S%'" { doc_body_append "Say hi to $first_names $last_name for me!<br>" } if_no_rows { doc_body_append "There aren't any users with last names beginnings with S!" } --
The new API keeps track of which handles are in use, and automatically allocates new handles when they are necessary (e.g., to perform subqueries while a select is active). For example: -
-+doc_body_append "<ul>" db_foreach select_names "select first_names, last_name, user_id from users" { @@ -224,101 +149,79 @@ doc_body_append "</ul>" db_release_unused_handles --+
A new handle isn't actually allocated and released for every selection, of course - as a performance optimization, the API keeps old handles around until db_release_unused_handles is invoked (or the script terminates). -
-Note that there is no analogue to ns_db gethandle - the -handle is always automatically allocated the first time it's needed.
-Introduction
-+
Note that there is no analogue to ns_db gethandle - the +handle is always automatically allocated the first time it's needed.
Introduction
Most SQL statements require that the code invoking the statement pass along data associated with that statement, usually obtained from the user. For instance, in order to delete a WimpyPoint presentation, a Tcl script might use the SQL statement -
-+-delete from wp_presentations where presentation_id = some_presentation_id +delete from wp_presentations where presentation_id = some_presentation_id ---where some_presentation_id is a number which is a valid +
+where some_presentation_id is a number which is a valid presentation ID of the presentation I want to delete. It's easy to write code handling situations like this since SQL statements can include -bind variables, which represent placeholders for actual +bind variables, which represent placeholders for actual data. A bind variable is specified as a colon followed by an identifier, so the statement above can be coded as: -
-+db_dml presentation_delete { delete from wp_presentations where presentation_id = :some_presentation_id } --+
When this SQL statement is invoked, the value for the bind variable :some_presentation_id is pulled from the Tcl variable $some_presentation_id (in the caller's environment). Note that bind variables are not limited to one per statement; you can use an arbitrary number, and each will pull from the correspondingly named Tcl variable. (Alternatively, you can also specify an list or ns_set -providing bind variables' values; see Usage.) -
-The value of a bind variable is taken literally by the database driver, so +providing bind variables' values; see Usage.) +
The value of a bind variable is taken literally by the database driver, so there is never any need to put single-quotes around the value for a bind variable, or to use db_quote to escape single-quotes contained -in the value. The following works fine, despite the apostrophe:
-+in the value. The following works fine, despite the apostrophe:set exclamation "That's all, folks!" db_dml exclamation_insert { insert into exclamations(exclamation) values(:exclamation) } --Note that you can use a bind variable in a SQL statement only where you +
Note that you can use a bind variable in a SQL statement only where you could use a literal (a number or single-quoted string). Bind variables cannot be placeholders for things like SQL keywords, table names, or column names, so the following will not work, even if $table_name is set -properly:
-+properly:select * from :table_name --Why Bind Variables Are Useful
-+
Why Bind Variables Are Useful
Why bother with bind variables at all - why not just write the Tcl statement above like this: -
-+db_dml presentation_delete " delete from wp_presentations where presentation_id = $some_presentation_id " --+
(Note the use of double-quotes to allow the variable reference to $some_presentation_id to be interpolated in.) This will work, but consider the case where some devious user causes some_presentation_id to be set to something like '3 or 1 = 1', which would result in the following statement being executed: -
-+delete from wp_presentations where presentation_id = 3 or 1 = 1 --+
This deletes every presentation in the database! Using bind variables eliminates this gaping security hole: since bind variable values are taken literally. Oracle will attempt to delete presentations whose presentation ID @@ -328,24 +231,15 @@ always considers the values of bind variables to be literals, it becomes more difficult for users to perform URL surgery to trick scripts into running dangerous queries and DML. -
-Usage
-Every db_* command accepting a SQL command as an argument -supports bind variables. You can either
-specify the -bind switch to provide a set with bind variable -values, or
specify the -bind switch to explicitly provide a list of -bind variable names and values, or
not specify a bind variable list at all, in which case Tcl variables are -used as bind variables.
+
Usage
Every db_* command accepting a SQL command as an argument +supports bind variables. You can either
specify the -bind switch to provide a set with bind variable +values, or
specify the -bind switch to explicitly provide a list of +bind variable names and values, or
not specify a bind variable list at all, in which case Tcl variables are +used as bind variables.
The default behavior (i.e., if the -bind switch is omitted) is that these procedures expect to find local variables that correspond in name to the referenced bind variables, e.g.: -
-+set user_id 123456 set role "administrator" @@ -361,14 +255,11 @@ # of "administrator" } --+
The value of the local Tcl variable user_id (123456) is bound to the user_id bind variable. -
-The -bind switch can takes the name of an ns_set -containing keys for each bind variable named in the query, e.g.:
-+The -bind switch can takes the name of an ns_set +containing keys for each bind variable named in the query, e.g.:
set bind_vars [ns_set create] ns_set put $bind_vars user_id 123456 @@ -385,12 +276,10 @@ # of "administrator" } --+
Alternatively, as an argument to -bind you can specify a list of alternating name/value pairs for bind variables: -
-+db_foreach user_group_memberships_by_role { select g.group_id, g.group_name @@ -403,23 +292,18 @@ # of "administrator" } -- -+
When processing a DML statement, Oracle coerces empty strings into -null. (This coercion does not occur in the +null. (This coercion does not occur in the WHERE clause of a query, i.e. col = '' and col is null are not equivalent.) -
-As a result, when using bind variables, the only way to make Oracle set a +
As a result, when using bind variables, the only way to make Oracle set a column value to null is to set the corresponding bind variable to the empty string, since a bind variable whose value is the string "null" will be interpreted as the literal string -"null".
-These Oracle quirks complicate the process of writing clear and abstract -DML difficult. Here is an example that illustrates why:
-+"null".These Oracle quirks complicate the process of writing clear and abstract +DML difficult. Here is an example that illustrates why:
# # Given the table: @@ -439,19 +323,15 @@ # null, because Oracle has coerced the empty string (even for the # numeric column "bar") into null in both cases --+
Since databases other than Oracle do not coerce empty strings into null, this code has different semantics depending on the underlying database (i.e., the row that gets inserted may not have null as its column values), which defeats the purpose of SQL abstraction. -
-Therefore, the Database Access API provides a database-independent way to +
Therefore, the Database Access API provides a database-independent way to represent null (instead of the Oracle-specific idiom of the -empty string): db_null.
-Use it instead of the empty string whenever you want to set a column value -explicitly to null, e.g.:
-+empty string): db_null.Use it instead of the empty string whenever you want to set a column value +explicitly to null, e.g.:
set bar [db_null] set baz [db_null] @@ -460,35 +340,23 @@ # # sets the values for both the "bar" and "baz" columns to null --
We now require that each SQL statement be assigned a logical name for the statement that is unique to the procedure or page in which it is defined. This is so that (eventually) we can implement logically named statements with alternative SQL for non-Oracle databases (e.g., Postgres). More on this later. -
-Normally, db_foreach, db_0or1row, and db_1row places the results of queries in Tcl variables, so you can say: -
-+db_foreach users_select "select first_names, last_name from users" { doc_body_append "<li>$first_names $last_name\n" } --+
However, sometimes this is not sufficient: you may need to examine the rows returned, to dynamically determine the set of columns returned by the query, or to avoid collisions with existing variables. You can use the @@ -497,8 +365,7 @@ instruct the database routines to place the results in a Tcl array or ns_set, respectively, where the keys are the column names and the values are the column values. For example: -
-+db_foreach users_select "select first_names, last_name from users" -column_set columns { # Now $columns is an ns_set. @@ -508,282 +375,143 @@ } } --+
will write something like: -
-first_names is Jon. last_name is Salz.
first_names is Lars. last_name is Pind.
first_names is Michael. last_name is Yoon.
-The database library can transparently maintain pools of sequence values, so -that each request for a new sequence value (using db_nextval) -does not incur a roundtrip to the server. For instance, this functionality is -very useful in the security/sessions library, which very frequently allocates -values from the sec_id_seq sequence. To utilize this -functionality for a particular sequence, register the sequence to be pooled, -either using the db_register_pooled_sequence procedure at server -startup time, or by including a configuration parameter of the form -
-- -PoolSequence.sequence_name_seq=count - --
-in any configuration section in the yourservername.ini -file, e.g., e.g., -
-
-
-[ns/server/yourservername/acs/security]
-PoolSequence.sec_id_seq=20
-
-
--The database library will allocate this number of sequence values at server -startup. It will periodically scan pools and allocate new values for -sequences which are less than half-full. (This normally occurs every 60 -seconds, and is configurable via the -PooledSequenceUpdateInterval parameter in the -[ns/server/yourservername/acs/database] configuration -section.) -
-+
first_names is Jon. last_name is Salz.
first_names is Lars. last_name is Pind.
first_names is Michael. last_name is Yoon.
Note that you never have to use ns_db anymore (including ns_db gethandle)! Just start doing stuff, and (if you want) call db_release_unused_handles when you're done as a hint to release the database handle. -
-
-db_abort_transaction
-
-Aborts all levels of a transaction. That is if this is called within -several nested transactions, all of them are terminated. Use this insetead of -db_dml "abort" "abort transaction". +
-db_null
-
-Returns a value which can be used in a bind variable to represent the SQL +
+db_null
+
Returns a value which can be used in a bind variable to represent the SQL value null. See Nulls and Bind Variables -above.
--db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ - [ -column_array array_name | -column_set set_name ] \ - code_block [ if_no_rows if_no_rows_block ] --
Performs the SQL query sql, executing -code_block once for each row with variables set to +above.
+db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ + [ -column_array array_name | -column_set set_name ] \ + code_block [ if_no_rows if_no_rows_block ] +
Performs the SQL query sql, executing +code_block once for each row with variables set to column values (or a set or array populated if -column_array or column_set is specified). If the query returns no rows, executes -if_no_rows_block (if provided).
-Example:
-+if_no_rows_block (if provided).Example:
db_foreach select_foo "select foo, bar from greeble" { doc_body_append "<li>foo=$foo; bar=$bar\n" } if_no_rows { doc_body_append "<li>There are no greebles in the database.\n" } --+
The code block may contain break statements (which terminate the loop and flush the database handle) and continue statements -(which continue to the next row of the loop).
--db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ - [ -column_array array_name | -column_set set_name ] --
Performs the SQL query sql, setting variables to -column values. Raises an error if the query does not return exactly 1 row.
-Example:
-+(which continue to the next row of the loop).
+db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ + [ -column_array array_name | -column_set set_name ] +
Performs the SQL query sql, setting variables to +column values. Raises an error if the query does not return exactly 1 row.
Example:
db_1row select_foo "select foo, bar from greeble where greeble_id = $greeble_id" # Bombs if there's no such greeble! # Now $foo and $bar are set. --
-db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ - [ -column_array array_name | -column_set set_name ] --
Performs the SQL query sql. If a row is returned, +
+db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ + [ -column_array array_name | -column_set set_name ] +
Performs the SQL query sql. If a row is returned, sets variables to column values and returns 1. If no rows are returned, -returns 0. If more than one row is returned, throws an error.
--db_nextval sequence-name --
Returns the next value for the sequence sequence-name (using a -SQL statement like SELECT sequence-name.nextval FROM -DUAL). If sequence pooling is enabled for the sequence, transparently -uses a value from the pool if available to save a round-trip to the database -(see Sequence Pooling). - -
--db_register_pooled_sequence sequence-name pool-size --
Registers the sequence sequence-name to be pooled, with a pool -size of pool-size sequence values (see Sequence Pooling). - -
--db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ] --
Returns the first column of the result of SQL query -sql. If sql doesn't return a -row, returns default (or throws an error if -default is unspecified). Analogous to +returns 0. If more than one row is returned, throws an error.
+db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ] +
Returns the first column of the result of SQL query +sql. If sql doesn't return a +row, returns default (or throws an error if +default is unspecified). Analogous to database_to_tcl_string and database_to_tcl_string_or_null. -
--db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ] --
Returns a Tcl list of the values in the first column of the result of SQL -query sql. If sql doesn't +
+db_nextval sequence-name +
Returns the next value for the sequence sequence-name (using a +SQL statement like SELECT sequence-name.nextval FROM +DUAL). If sequence pooling is enabled for the sequence, transparently +uses a value from the pool if available to save a round-trip to the database. + +
+db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +
Returns a Tcl list of the values in the first column of the result of SQL +query sql. If sql doesn't return any rows, returns an empty list. Analogous to database_to_tcl_list. -
--db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ] --
Returns a Tcl list, each element of which is a list of all column values -in a row of the result of SQL query sql. If -sql doesn't return any rows, returns an empty list. +
+db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +
Returns a Tcl list, each element of which is a list of all column values +in a row of the result of SQL query sql. If +sql doesn't return any rows, returns an empty list. (Analogous to database_to_tcl_list_list.) -
--db_dml statement-name sql \ - [ -bind bind_set_id | -bind bind_value_list ] \ - [ -blobs blob_list | -clobs clob_list | - -blob_files blob_file_list | -clob_files clob_file_list ] --
Performs the DML or DDL statement sql.
-If a length-n list of blobs or clobs is provided, then the SQL -should return n blobs or clobs into the bind variables -:1, :2, ... :n. -blobs or clobs, if specified, +
+db_list_of_ns_sets statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +
+ Returns a list of ns_sets with the values of each column of each row + returned by the sql query specified. +
+db_dml statement-name sql \ + [ -bind bind_set_id | -bind bind_value_list ] \ + [ -blobs blob_list | -clobs clob_list | + -blob_files blob_file_list | -clob_files clob_file_list ] +
Performs the DML or DDL statement sql.
If a length-n list of blobs or clobs is provided, then the SQL +should return n blobs or clobs into the bind variables +:1, :2, ... :n. +blobs or clobs, if specified, should be a list of individual BLOBs or CLOBs to insert; -blob_files or clob_files, if -specified, should be a list of paths to files containing the data to +blob_files or clob_files, if +specified, should be a list of paths to files containing the data to insert. Only one of -blobs, -clobs, --blob_files, and -clob_files may be provided.
-Example:
-+-blob_files, and -clob_files may be provided.Example:
db_dml insert_photos " insert photos(photo_id, image, thumbnail_image) values(photo_id_seq.nextval, empty_blob(), empty_blob()) returning image, thumbnail_image into :1, :2 " -blob_files [list "/var/tmp/the_photo" "/var/tmp/the_thumbnail"] --+
This inserts a new row into the photos table, with the contents of the files /var/tmp/the_photo and /var/tmp/the_thumbnail in the image and thumbnail columns, respectively. -
--db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +
+db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] -db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] -db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ] --
Analagous to ns_ora write_clob/write_blob/blob_get_file. +db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +
Analagous to ns_ora write_clob/write_blob/blob_get_file. -
-
-db_release_unused_handles
-
-Releases any allocated, unused database handles.
--db_transaction code_block [ on_error { code_block } ] --
Executes code_block transactionally. Nested +
+db_release_unused_handles
+
Releases any allocated, unused database handles.
+db_transaction code_block [ on_error { code_block } ] +
Executes code_block transactionally. Nested transactions are supported (end transaction is transparently ns_db dml'ed when the outermost transaction completes). The db_abort_transaction command can be used to abort all levels of transactions. It is possible to specify an optional on_error -code block that will be executed if some code in code_block throws +code block that will be executed if some code in code_block throws an exception. The variable errmsg will be bound in that scope. -If there is no on_error code, any errors will be propagated.
-Example:
-+If there is no on_error code, any errors will be propagated.Example:
proc replace_the_foo { col } { db_transaction { @@ -812,30 +540,84 @@ print_the_foo ; # Writes out "foo is 8" --
-db_resultrows
-
-Returns the number of rows affected or returned by the previous +
+db_abort_transaction
+
Aborts all levels of a transaction. That is if this is called within +several nested transactions, all of them are terminated. Use this insetead of +db_dml "abort" "abort transaction". + + +
+db_multirow [ -local ] [ -append ] [ -extend column_list ] \ + var-name statement-name sql \ + [ -bind bind_set_id | -bind bind_value_list ] \ + code_block [ if_no_rows if_no_rows_block ] +
+ Performs the SQL query sql, saving results in variables + of the form + var_name:1, var_name:2, etc, + setting var_name:rowcount to the total number + of rows, and setting var_name:columns to a + list of column names. +
+ Each row also has a column, rownum, automatically + added and set to the row number, starting with 1. Note that this will + override any column in the SQL statement named 'rownum', also if you're + using the Oracle rownum pseudo-column. +
+ If the -local is passed, the variables defined + by db_multirow will be set locally (useful if you're compiling dynamic templates + in a function or similar situations). +
+ You may supply a code block, which will be executed for each row in + the loop. This is very useful if you need to make computations that + are better done in Tcl than in SQL, for example using ns_urlencode + or ad_quotehtml, etc. When the Tcl code is executed, all the columns + from the SQL query will be set as local variables in that code. Any + changes made to these local variables will be copied back into the + multirow. +
+ You may also add additional, computed columns to the multirow, using the + -extend { col_1 col_2 ... } switch. This is + useful for things like constructing a URL for the object retrieved by + the query. +
+ If you're constructing your multirow through multiple queries with the + same set of columns, but with different rows, you can use the + -append switch. This causes the rows returned by this query + to be appended to the rows already in the multirow, instead of starting + a clean multirow, as is the normal behavior. The columns must match the + columns in the original multirow, or an error will be thrown. +
+ Your code block may call continue in order to skip a row + and not include it in the multirow. Or you can call break + to skip this row and quit looping. +
+ + Notice the nonstandard numbering (everything + else in Tcl starts at 0); the reason is that the graphics designer, a non + programmer, may wish to work with row numbers. +
+ Example: +
+db_multirow -extend { user_url } users users_query { + select user_id first_names, last_name, email from cc_users +} { + set user_url [acs_community_member_url -user_id $user_id] +} +
+db_resultrows
+
Returns the number of rows affected or returned by the previous statement. -
--db_with_handle var code_block --
Places a database handle into the variable var and -executes code_block. This is useful when you don't +
+db_with_handle var code_block +
Places a database handle into the variable var and +executes code_block. This is useful when you don't want to have to use the new API (db_foreach, -db_1row, etc.), but need to use database handles explicitly.
-Example:
-+db_1row, etc.), but need to use database handles explicitly.Example:
proc lookup_the_foo { foo } { db_with_handle db { @@ -853,71 +635,102 @@ } } --
-db_nullify_empty_string string --
For true SQL purists, we provide the convenience function -db_nullify_empty_string, which returns -[db_null] if its string argument is the empty string -and can be used to encapsulate another Oracle quirk:
-- -set baz "" - -# Clean out the foo table -# -db_dml unused "delete from foo" - -db_dml unused "insert into foo(baz) values('$baz')" - -set n_rows [db_string unused "select count(*) from foo where baz is null"] -# -# $n_rows is 1; in effect, the "baz is null" criterion is matching -# the empty string we just inserted (because of Oracle's coercion -# quirk) - --
-To balance out this asymmetry, you can explicitly set baz to -null by writing: -
-- -db_dml foo_insert "insert into foo(baz) values(:1)" {[db_nullify_empty_string $baz]} - --
+
By Pete Su and Jon Salz. Modified by Roberto Mello. -
-+
One of OpenACS's great strengths is that code written for it is very close to the database. It is very easy to interact with the database from anywhere within OpenACS. Our goal is to develop a coherent API for database access which makes this even easier. -
-+
+ More detailed information about the DB api is available at + Database Access API. +
Here's a typical block of code from an OpenACS 3.x dynamic page: -
-+set tcl_var "foo" set db [ns_db gethandle] @@ -74,47 +42,33 @@ } ns_db releasehandle $db --+
Writing code like this had the following annoyances: -
+
It was repetitive, tedious and error prone to write the same type of loops over and over again. -
+
Using Tcl variable interpolation in a literal string, to pass values from the page to the database, is error prone, relatively inefficient, and a good way to compromise the security of a web site. -
+
Magic like set_variables_after_query made code confusing. -
+
The scope of transactions is not clear from reading the code. -
+
Passing handles around explicitly made it easy to use them in bad ways, like holding a handle for too long while returning data to a user's browser. -
-
-+
Introduced in ACS 3.4, the new Database API is meant to save developers from the above tedium and provide a more structured syntax for specifying database operations, including transactions. -
-Here is how you would code up the example above using the new API. -
-+set count 0 set tcl_var "foo" @@ -136,82 +90,62 @@ incr count } } --+
There are several things to note here: -
+
No explicit code for grabbing and releasing handles. Usage of the Database API implicitly deals with all handle management issues. -
+
The new command db_transaction makes the scope of a transaction clear. db_transaction takes the code block argument and automatically runs it in the context of a transaction. -
+
The new command db_foreach writes our old while loop for us. -
+
Every SQL query has a name, meant to be unique within the server instance (though this is not enforced). -
+
Finally and most importantly, there is a new scheme for passing data from a Tcl variable to the database, which we'll cover next. -
-
-Bind variables are placeholders for literal values in an SQL query being sent to the server. Take the example query above: in the old way, data was generally passed to Oracle directly, via Tcl string interpolation. So in the example above, the actual query we send would look like this: -
-+select foo, bar, baz from some_table, some_other_table where some_table.id=some_other_table.id and some_table.condition_p = 'foo' --+
There are a few problems with this: -
-+
Third, no type checking occurs on the literal value. Finally, if the Tcl variable is passed in or between web forms or otherwise subject to external modification, there is nothing keeping malicious users from setting the Tcl variable to some string that changes the query textually. -
-+
This type of attack, - called SQL smuggling, can be very + called SQL smuggling, can be very damaging - entire tables can be exposed or have their contents deleted, for example. Another very important reason for using bind variables is performance. Oracle caches @@ -222,28 +156,22 @@ the same) while SQL statements that do not use bind variables will not match unless the values in the statement are exactly the same. This will improve performance considerably. -
-+
To fix all these problems, we replace literal values in the query with a placeholder character, and then send the data along after. So the query looks like this: -
-+select foo, bar, baz from some_table, some_other_table where some_table.id = some_other_table.id and some_table.condition_p = ? --+
The '?' character means "This will be filled in later with literal data". In use, you might write code that looks like this: -
-+set statement [prepare_query " select foo, @@ -255,93 +183,73 @@ "] [bind_param $statement 1 $tcl_var] --+
The above example is meant to be psuedo-Tcl - no API like this actually exists. What happens is that we first send the SQL statement - to the server for parsing, then later we bind values to the + to the server for parsing, then later we bind values to the placeholders, and send those values along seperately. This seperate - binding step is where the term bind variable comes from. -
-+ binding step is where the term bind variable comes from. +
This split has several advantages. First, type checking happens on the literal. If the column we are comparing against holds numbers, and we send a string, we get a nice error. Second, since string literals are no longer in the query, no extra quoting is required. Third, substitution of bind variables cannot change the actual text of the query, only the literal values in the placeholders. -
-+
The database API makes bind variables easy to use by hooking them smoothly into the Tcl runtime. Rather than using a '?' as a generic placeholder, you use a colon followed by the name of the Tcl variable that you wish to pass as a literal. So here's the final, real-life form of the example query: -
-+select foo, bar, baz from some_table, some_other_table where some_table.id = some_other_table.id and some_table.condition_p = :tcl_var --+
The database API parses the query and pulls out all the bind variable specifications and replaces them with generic placeholders. It then automatically pulls the values of the named Tcl vars out of the runtime environment of the script, and passes them to the database. -
-+
Note that while this looks like a simple syntactic change, it really is very different from how we've written queries in the past. You use bind variables to replace what would otherwise be a literal value in a query, and Tcl style string interpolation does not happen. So you cannot do something like: -
-+set table "baz" set condition "where foo = bar" db_foreach my_query { select :table from some_table where :condition } --+
SQL will not allow a literal to occur where we've put the bind variables, so the query is syntactically incorrect. You have to remember that while the bind variable syntax looks similar to variable - interpolation in Tcl, it is not the same thing at all. -
-+ interpolation in Tcl, it is not the same thing at all. +
Finally, the DB API has several different styles for passing bind variable values to queries. In general, use the style presented here because it is the most convenient. -
-Every db_* command accepting a SQL command as an argument - supports bind variables. You can either
-+
Every db_* command accepting a SQL command as an argument + supports bind variables. You can either
Specify the -bind switch to provide a set with bind variable values, or -
+
Specify the -bind switch to explicitly provide a list of bind variable names and values, or -
+
Not specify a bind variable list at all, in which case Tcl variables are used as bind variables. -
+
The default behavior (i.e., if the -bind switch is omitted) is that these procedures expect to find local variables that correspond in name to the referenced bind variables, e.g.: -
-+set user_id 123456 set role "administrator" @@ -357,14 +265,11 @@ # of "administrator" } --+
The value of the local Tcl variable user_id (123456) is bound to the user_id bind variable. -
-The -bind switch can takes the name of an ns_set - containing keys for each bind variable named in the query, e.g.:
-+The -bind switch can takes the name of an ns_set + containing keys for each bind variable named in the query, e.g.:
set bind_vars [ns_set create] ns_set put $bind_vars user_id 123456 @@ -381,12 +286,10 @@ # of "administrator" } --+
Alternatively, as an argument to -bind you can specify a list of alternating name/value pairs for bind variables: -
-+db_foreach user_group_memberships_by_role { select g.group_id, g.group_name @@ -399,26 +302,18 @@ # of "administrator" } --
When processing a DML statement, Oracle coerces empty strings into - null. (This coercion does not occur in the + null. (This coercion does not occur in the WHERE clause of a query, i.e. col = '' and col is null are not equivalent.) -
-As a result, when using bind variables, the only way to make Oracle set a +
As a result, when using bind variables, the only way to make Oracle set a column value to null is to set the corresponding bind variable to the empty string, since a bind variable whose value is the string "null" will be interpreted as the literal string - "null".
-These Oracle quirks complicate the process of writing clear and abstract - DML difficult. Here is an example that illustrates why:
-+ "null".These Oracle quirks complicate the process of writing clear and abstract + DML difficult. Here is an example that illustrates why:
# # Given the table: @@ -438,19 +333,15 @@ # null, because Oracle has coerced the empty string (even for the # numeric column "bar") into null in both cases --+
Since databases other than Oracle do not coerce empty strings into null, this code has different semantics depending on the underlying database (i.e., the row that gets inserted may not have null as its column values), which defeats the purpose of SQL abstraction. -
-Therefore, the Database Access API provides a database-independent way to +
Therefore, the Database Access API provides a database-independent way to represent null (instead of the Oracle-specific idiom of the - empty string): db_null.
-Use it instead of the empty string whenever you want to set a column value - explicitly to null, e.g.:
-+ empty string): db_null.Use it instead of the empty string whenever you want to set a column value + explicitly to null, e.g.:
set bar [db_null] set baz [db_null] @@ -459,13 +350,7 @@ # # sets the values for both the "bar" and "baz" columns to null --
The database library can transparently maintain pools of sequence values, so that each request for a new sequence value (using db_nextval) does not incur a roundtrip to the server. For instance, this functionality is @@ -474,324 +359,291 @@ functionality for a particular sequence, register the sequence to be pooled, either using the db_register_pooled_sequence procedure at server startup time, or by including a configuration parameter of the form -
-+-PoolSequence.sequence_name_seq=count +PoolSequence.sequence_name_seq=count --- in any configuration section in the yourservername.ini +
+ in any configuration section in the yourservername.ini file, e.g., e.g., -
-+-[ns/server/yourservername/acs/security] +[ns/server/yourservername/acs/security] PoolSequence.sec_id_seq=20 --+
The database library will allocate this number of sequence values at server startup. It will periodically scan pools and allocate new values for sequences which are less than half-full. (This normally occurs every 60 seconds, and is configurable via the PooledSequenceUpdateInterval parameter in the [ns/server/ - yourservername + yourservername /acs/database] configuration section.) -
-The Database API has several functions that wrap familiar parts of the AOLserver database API. -
-+
Note that you never have to use ns_db anymore (including ns_db gethandle)! Just start doing stuff, and (if you want) call db_release_unused_handles when you're done as a hint to release the database handle. -
-+
db_abort_transaction --
Aborts all levels of a transaction. That is if this is called within +
Aborts all levels of a transaction. That is if this is called within several nested transactions, all of them are terminated. Use this insetead of db_dml "abort" "abort transaction". -
-+db_multirow [ -local ] [ -append ] [ -extend column_list ] \ + var-name statement-name sql \ + [ -bind bind_set_id | -bind bind_value_list ] \ + code_block [ if_no_rows if_no_rows_block ] +
+ Performs the SQL query sql, saving results in variables + of the form + var_name:1, var_name:2, etc, + setting var_name:rowcount to the total number + of rows, and setting var_name:columns to a + list of column names. +
+ Each row also has a column, rownum, automatically + added and set to the row number, starting with 1. Note that this will + override any column in the SQL statement named 'rownum', also if you're + using the Oracle rownum pseudo-column. +
+ If the -local is passed, the variables defined + by db_multirow will be set locally (useful if you're compiling dynamic templates + in a function or similar situations). +
+ You may supply a code block, which will be executed for each row in + the loop. This is very useful if you need to make computations that + are better done in Tcl than in SQL, for example using ns_urlencode + or ad_quotehtml, etc. When the Tcl code is executed, all the columns + from the SQL query will be set as local variables in that code. Any + changes made to these local variables will be copied back into the + multirow. +
+ You may also add additional, computed columns to the multirow, using the + -extend { col_1 col_2 ... } switch. This is + useful for things like constructing a URL for the object retrieved by + the query. +
+ If you're constructing your multirow through multiple queries with the + same set of columns, but with different rows, you can use the + -append switch. This causes the rows returned by this query + to be appended to the rows already in the multirow, instead of starting + a clean multirow, as is the normal behavior. The columns must match the + columns in the original multirow, or an error will be thrown. +
+ Your code block may call continue in order to skip a row + and not include it in the multirow. Or you can call break + to skip this row and quit looping. +
+ + Notice the nonstandard numbering (everything + else in Tcl starts at 0); the reason is that the graphics designer, a non + programmer, may wish to work with row numbers. +
+ Example: +
+db_multirow -extend { user_url } users users_query { + select user_id first_names, last_name, email from cc_users +} { + set user_url [acs_community_member_url -user_id $user_id] +} +
+
db_null --
+
Returns a value which can be used in a bind variable to represent the SQL value null. See Nulls and Bind Variables above. -
--db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ - [ -column_array array_name | -column_set set_name ] \ - code_block [ if_no_rows if_no_rows_block ] --
- Performs the SQL query +
+db_foreach statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ + [ -column_array array_name | -column_set set_name ] \ + code_block [ if_no_rows if_no_rows_block ] +
+ Performs the SQL query sql - , executing - code_block - once for each row + , executing + code_block + once for each row with variables set to column values (or a set or array populated if -column_array or column_set is specified). If the query returns no rows, executes - if_no_rows_block - (if provided). -
-Example:
-+ if_no_rows_block + (if provided). +Example:
db_foreach select_foo "select foo, bar from greeble" { doc_body_append "<li>foo=$foo; bar=$bar\n" } if_no_rows { doc_body_append "<li>There are no greebles in the database.\n" } --+
The code block may contain break statements (which terminate the loop and flush the database handle) and continue statements - (which continue to the next row of the loop).
--db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ - [ -column_array array_name | -column_set set_name ] --
- Performs the SQL query - sql, +
+db_1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ + [ -column_array array_name | -column_set set_name ] +
+ Performs the SQL query + sql, setting variables to column values. Raises an error if the query does not return exactly 1 row. -
-Example:
-+Example:
db_1row select_foo "select foo, bar from greeble where greeble_id = $greeble_id" # Bombs if there's no such greeble! # Now $foo and $bar are set. --
-db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ - [ -column_array array_name | -column_set set_name ] --
+
+db_0or1row statement-name sql [ -bind bind_set_id | -bind bind_value_list ] \ + [ -column_array array_name | -column_set set_name ] +
Performs the SQL query - sql. + sql. If a row is returned, sets variables to column values and returns 1. If no rows are returned, returns 0. If more than one row is returned, throws an error. -
-
-db_nextval sequence-name
-
-- Returns the next value for the sequence sequence-name (using a +
+db_nextval sequence-name
+
+ Returns the next value for the sequence sequence-name (using a SQL statement like SELECT - sequence-name.nextval FROM + sequence-name.nextval FROM DUAL). If sequence pooling is enabled for the sequence, transparently uses a value from the pool if available to save a round-trip to the database - (see Sequence Pooling). -
--db_register_pooled_sequence sequence-name pool-size --
Registers the sequence sequence-name to be pooled, with a pool - size of pool-size sequence values - (see Sequence Pooling). +
+db_register_pooled_sequence sequence-name pool-size +
Registers the sequence sequence-name to be pooled, with a pool + size of pool-size sequence values + (see Sequence Pooling). -
--db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ] --
Returns the first column of the result of SQL query - sql. - If sql doesn't return a +
+db_string statement-name sql [ -default default ] [ -bind bind_set_id | -bind bind_value_list ] +
Returns the first column of the result of SQL query + sql. + If sql doesn't return a row, returns - default + default (or throws an error if - default is unspecified). Analogous to + default is unspecified). Analogous to database_to_tcl_string and database_to_tcl_string_or_null. -
--db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ] --
Returns a Tcl list of the values in the first column of the result of SQL +
+db_list statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +
Returns a Tcl list of the values in the first column of the result of SQL query - sql. - If sql doesn't + sql. + If sql doesn't return any rows, returns an empty list. Analogous to database_to_tcl_list. -
--db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ] --
Returns a Tcl list, each element of which is a list of all column values - in a row of the result of SQL query sql. If - sql doesn't return any rows, returns an empty list. +
+db_list_of_lists statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +
Returns a Tcl list, each element of which is a list of all column values + in a row of the result of SQL query sql. If + sql doesn't return any rows, returns an empty list. (Analogous to database_to_tcl_list_list.) -
--db_dml statement-name sql \ - [ -bind bind_set_id | -bind bind_value_list ] \ - [ -blobs blob_list | -clobs clob_list | - -blob_files blob_file_list | -clob_files clob_file_list ] --
Performs the DML or DDL statement sql.
-If a length-n list of blobs or clobs is provided, then the SQL - should return n blobs or clobs into the bind variables - :1, :2, ... :n. - blobs or clobs, if specified, +
+db_dml statement-name sql \ + [ -bind bind_set_id | -bind bind_value_list ] \ + [ -blobs blob_list | -clobs clob_list | + -blob_files blob_file_list | -clob_files clob_file_list ] +
Performs the DML or DDL statement sql.
If a length-n list of blobs or clobs is provided, then the SQL + should return n blobs or clobs into the bind variables + :1, :2, ... :n. + blobs or clobs, if specified, should be a list of individual BLOBs or CLOBs to insert; - blob_files or clob_files, if - specified, should be a list of paths to files containing the data to + blob_files or clob_files, if + specified, should be a list of paths to files containing the data to insert. Only one of -blobs, -clobs, - -blob_files, and -clob_files may be provided.
-Example:
-+ -blob_files, and -clob_files may be provided.Example:
db_dml insert_photos " insert photos(photo_id, image, thumbnail_image) values(photo_id_seq.nextval, empty_blob(), empty_blob()) returning image, thumbnail_image into :1, :2 " -blob_files [list "/var/tmp/the_photo" "/var/tmp/the_thumbnail"] --+
This inserts a new row into the photos table, with the contents of the files /var/tmp/the_photo and /var/tmp/the_thumbnail in the image and thumbnail columns, respectively. -
--db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +
+db_write_clob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] -db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +db_write_blob statement-name sql [ -bind bind_set_id | -bind bind_value_list ] -db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ] --
Analagous to ns_ora write_clob/write_blob/blob_get_file. +db_blob_get_file statement-name sql [ -bind bind_set_id | -bind bind_value_list ] +
Analagous to ns_ora write_clob/write_blob/blob_get_file. -
-+
db_release_unused_handles --
Releases any allocated, unused database handles.
--db_transaction code_block [ on_error { code_block } ] --
Executes code_block transactionally. Nested +
Releases any allocated, unused database handles.
+db_transaction code_block [ on_error { code_block } ] +
Executes code_block transactionally. Nested transactions are supported (end transaction is transparently ns_db dml'ed when the outermost transaction completes). The db_abort_transaction command can be used to abort all levels of transactions. It is possible to specify an optional on_error - code block that will be executed if some code in code_block throws + code block that will be executed if some code in code_block throws an exception. The variable errmsg will be bound in that scope. - If there is no on_error code, any errors will be propagated.
-Example:
-+ If there is no on_error code, any errors will be propagated.Example:
proc replace_the_foo { col } { db_transaction { @@ -820,30 +672,18 @@ print_the_foo ; # Writes out "foo is 8" --
+
db_resultrows --
Returns the number of rows affected or returned by the previous +
Returns the number of rows affected or returned by the previous statement. -
--db_with_handle var code_block --
Places a database handle into the variable var and - executes code_block. This is useful when you don't +
+db_with_handle var code_block +
Places a database handle into the variable var and + executes code_block. This is useful when you don't want to have to use the new API (db_foreach, - db_1row, etc.), but need to use database handles explicitly.
-Example:
-+ db_1row, etc.), but need to use database handles explicitly.Example:
proc lookup_the_foo { foo } { db_with_handle db { @@ -861,24 +701,18 @@ } } --
-db_nullify_empty_string string
-
-For true SQL purists, we provide the convenience function +
+db_nullify_empty_string string
+
For true SQL purists, we provide the convenience function db_nullify_empty_string, which returns - [db_null] if its string argument is the empty string - and can be used to encapsulate another Oracle quirk:
-+ [db_null] if its string argument is the empty string + and can be used to encapsulate another Oracle quirk:set baz "" @@ -894,46 +728,15 @@ # the empty string we just inserted (because of Oracle's coercion # quirk) --+
To balance out this asymmetry, you can explicitly set baz to null by writing: -
-+db_dml foo_insert "insert into foo(baz) values(:1)" {[db_nullify_empty_string $baz]} --
-
+
+
+
By claus@arsdigita.com, with additions by Roberto Mello and the OpenACS Community -
-+
ArsDigita created a good documentation ground for us to build - upon. Some sections of the documentation however, lack details - and examples, others simply are inexistent.Our goal is to give + upon. Some sections of the documentation, however, lack details + and examples; others are simply nonexistant. Our goal is to give OpenACS a superb documentation, so that users, developers and administrators of OpenACS installations can enjoy the system. -
-+
OpenACS™ is a powerful system, with incredible possibilities and applications, but with this power comes some complexity and a learning curve that will only be atenuated by good documentation. This is what we are after. -
-+
The documentation for OpenACS™ is written using DocBook XML. The reasons why we are using DocBook are explained in more details in the Why DocBook? section. I will add the reasons why we are using Docbook XML instead of Docbook SGML: -
-In order to separate content and presentation, all OpenACS documentation will be marked up to conform to the DocBook XML DTD - + This enables us to publish in a variety of formats and relieves each contributor of the burden of presentation, freeing him to focus on content and sharing knowledge. -
-+
Theoretically any strict DTD would have been sufficient - we could even write our own. But DocBook has been around for a while (since early 90's), it's well-tested, it's complete, it's extremely well-suited for technical documents @@ -88,200 +45,137 @@ and a number of free and commercial tools are available for editing and publishing DocBook documents. -
-+
This primer walks you through the basics, and should cover the needs for 95 percent of the documentation we produce. However, you're always welcome to check out DocBook's list of elements and use more exotic features in your documents. The list is made up of SGML-elements but basically - the same elements are valid in the XML DTD as long as you remember to: - -
-You are going to need the following to work with the OpenACS Docbook XML documentation: -
-After you have the tools mentioned above, you need to define a title for your document. Then start thinking about the possible sections and subsections you will have in your document. Make sure you coordinate with the OpenACS Gatekeepers to make sure you're not writing something that someone else is already writing. Also, if you desire to use the OpenACS CVS repository, please e-mail the gatekeeper in charge of documentation. -
-+
You can look at some templates for documents (in Docbook XML) in the sources - for acs-core-docs, especially the - Detailed Design Documentation Template and the - System/Application Requirements Template. -
-+ for acs-core-docs, especially the + Detailed Design Documentation Template and the + System/Application Requirements Template. +
The documentation for each package will make up a little "book" that is structured like this - - examples are emphasized: + - examples are emphasized: - + -
-- book : Docs for one package - templating ++ book : Docs for one package - templating | - +--chapter : One section - for developers + +--chapter : One section - for developers | ---------+------------------------------------------------------ | - +--sect1 : Single document - requirements + +--sect1 : Single document - requirements | - +--sect2 : Sections - functional requirements + +--sect2 : Sections - functional requirements | - +--sect3 : Subsections - Programmer's API + +--sect3 : Subsections - Programmer's API | - ... : ... --+ ... : ... +
The actual content is split up into documents that start at a sect1-level. These are then tied together in a top-level document that contains all the information above the line. This will be explained in more detail in a later document, - and we will provide a set of templates for documenting an entire package.
-For now you can take a look at the + and we will provide a set of templates for documenting an entire package.
For now you can take a look at the sources of these DocBook documents to get an idea of how they are tied together. -
-+ Given that your job starts at the sect1-level, all your documents should open with a <sect1>-tag and end with the corresponding </sect1>. -
-+ You need to feed every <sect1> two attributes. The first attribute, id, is standard and can be used with all elements. It comes in very handy when interlinking between documents (more about this when talking about links in the section called “Links”). The value of id has to be unique throughout the book you're making since the id's in your sect1's will turn into filenames when the book is parsed into HTML. -
-+ The other attribute is xreflabel. The value of this is the text that will appear as the link when referring to this sect1. -
-+
Right after the opening tag you put the title of the document - this is usually the same as xreflabel-attribute. E.g. the top level of the document you're reading right now looks like this: -
-+<sect1 id="docbook-primer" xreflabel="aD DocBook Primer"> <title>aD DocBook Primer</title> ... </sect1> --
+ Inside this container your document will be split up into <sect2>'s, each with the same requirements - id and xreflabel attributes, and a <title>-tag inside. Actually, the xreflabel is never required in sections, but it makes linking to that section a lot easier. -
-+
When it comes to naming your sect2's and below, prefix them with some abbreviation of the id in the sect1 such as requirements-overview. -
-+ For displaying a snippet of code, a filename or anything else you just want to appear as a part of a sentence, we will use the tag <computeroutput>. This takes the place of the HTML-tag <code> -
-+
For bigger chunks of code such as SQL-blocks, the tag <programlisting> is used. Just wrap your code block in it; mono-spacing, indents and all that stuff is taken care of automatically. -
-+ Linking falls into two different categories: inside the book you're making and outside: -
-+
By having unique id's you can cross-reference any part of your book with a simple tag, regardless of where that part is. -
--Check out how I link to a subsection of the Developer's Guide:
-+Check out how I link to a subsection of the Developer's Guide:
Put this in your XML: @@ -294,21 +188,14 @@ - Find information about creating a package in Making a Package --+
Note that even though this is an empty tag, you have to either: -
-+
Provide the end-tag, </xref>, or -
+
Put a slash before the ending-bracket: <xref linkend="blahblah"/> -
If the section you link to hasn't a specified xreflabel-attribute, - the link is going to look like this:
-+
If the section you link to hasn't a specified xreflabel-attribute, + the link is going to look like this:
Put this in your XML: @@ -321,51 +208,33 @@ - Find information about what a package looks like in the section called “What a Package Looks Like” --
+
Note that since I haven't provided an xreflabel for the subsection, packages-looks, the parser will try its best to explain where the link takes you. -
-+ If you're hyper-linking out of the documentation, it works almost the same way as HTML - the tag is just a little different (<ulink>): -
-<ulink url="http://www.oracle.com/">Oracle Corporation</ulink>-
+
<ulink url="http://www.oracle.com/">Oracle Corporation</ulink>
....will create a hyper-link to Oracle in the HTML-version of the documentation. -
--NOTE: Do NOT use ampersands in your hyper links. These are reserved for referencing +
NOTE: Do NOT use ampersands in your hyper links. These are reserved for referencing entities, which is exactly how you'll make an ampersand: & -
-+ NOTE: Currently this section currently only takes HTML-output into consideration - + not a printed version +
+ + Another Note: Also, it's still not a 100 percent sure that this is how we are going to do it, so if you want to start converting your documents right away, start out with the ones without graphics ;) - -
-+ To insert a graphic we use the elements <mediaobject>, <imageobject>, @@ -375,8 +244,7 @@ and one for print (EPS). Finally you should provide a brief description wrapped in <textobject> - in HTML this will be the ALT text. -
-+<mediaobject> <imageobject> <imagedata fileref="../images/rp-flow.gif" format="GIF" align="center"/> @@ -388,62 +256,41 @@ <phrase>This is an image of the flow in the Request Processor</phrase> </textobject> </mediaobject> --+
Put your graphics in a separate directory ("images") and link to them only with relative paths. -
-+ Here's how you make the DocBook equivalent of the three usual HTML-lists: -
-+
Making an unordered list is pretty much like doing the same thing in HTML - if you close your <li>, that is. The only differences are that each list item has to be wrapped in something more, such as <para>, and that the tags are called <itemizedlist> and <listitem>: -
-+<itemizedlist> <listitem><para>Stuff goes here</para><listitem> <listitem><para>More stuff goes here</para><listitem> </itemizedlist> --
+
The ordered list is like the preceding, except that you use - <orderedlist> instead:
-+ <orderedlist> instead:<orderedlist> <listitem><para>Stuff goes here</para><listitem> <listitem><para>More stuff goes here</para><listitem> </orderedlist> --
+
This kind of list is called a variablelist and these are the tags you'll need to make it happen: <variablelist>, <varlistentry>, <term> and - <listitem>:
-+ <listitem>:<variablelist> <varlistentry> @@ -457,20 +304,12 @@ </varlistentry> </variablelist> --
+ DocBook supports several types of tables, but in most cases, the <informaltable> is enough: -
-+<informaltable frame="all"> <tgroup cols="3"> <tbody> @@ -496,218 +335,92 @@ </tbody> </tgroup> </informaltable> --+
With our current XSL-style-sheet, the output of the markup above will be a simple HTML-table: -
---
- - -- - - - -a1 -b1 -c1 -- -a2 -b2 -c2 -- - -a3 -b3 -c3 -
+
a1 b1 c1 a2 b2 c2 a3 b3 c3
If you want cells to span more than one row or column, it gets a bit more complicated - check out <table> for an example. -
-+ Our documentation uses two flavors of emphasis - italics and bold type. DocBook uses one - <emphasis>. -
-+
The <emphasis> tag defaults to italics when parsed. If you're looking for emphasizing with bold type, use <emphasis role="strong">. -
-Marking up index-words may not have any importance for the HTML-output, but in order to make it easier to make a nice print-version of the documentation, you should mark up words in your documents that you would like to see show up in an index one day. -
-+
Use <indexterm>, <primary> and <secondary> for this. See these links for an explanation. -
-Once you have the Docbook Tools installed, you can convert your xml documents to HTML (or other formats. Let me know if you are able to convert to other formats). -
-+
With the DocBook XSL stylesheets, generation of multiple files is controlled by the stylesheet. If you want to generate a single file, you call one stylesheet. If you want to generate multiple files, you call a different stylesheet. -
-+
To generate a single HTML file from your DocBook XML file, use the command: -
-+bash$ xsltproc -o outputfilename.xml /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/html/html.xsl filename.xml ---Note
- This example uses Daniel Veillard's xsltproc command available +-Note
+ This example uses Daniel Veillard's xsltproc command available as part of libxslt from http://www.xmlsoft.org/XSLT/. If you are using other XML processors such as Xalan or Saxon, you will need to change the command line appropriately. -+
To generate a set of linked HTML pages, with a separate page for each <chapter>, <sect1> or <appendix> tag, use the following command: -
-+bash$ xsltproc /usr/share/sgml/docbook/stylesheet/xsl/nwalsh/html/chunk.xsl filename.xml --
+
David Lutterkort wrote an intro to the PSGML Mode in Emacs -
+
For checking if your document is well-formed, James Clark's free Java parser, XP, is recommended. (note that it is not a validating parser, but as long as you follow the guidelines set forth in this - document, your XML will validate)
+ document, your XML will validate)
DocBook Tool for Linux: Let's you convert your docbook documents to a number of formats. Sometimes it's nice to see - how you stuff looks. NOTE: I only got these to + how you stuff looks. NOTE: I only got these to work with Docbook SGML, NOT with Docbook XML. If you are - able to make it work with our XML, please let us know. -
+ able to make it work with our XML, please let us know. +
AptConvert from PIXware is a Java editor that will produce DocBook documents and let you transform them into HTML and PDF for a local preview before you submit. -
+
In the process of transforming your HTML into XML, HTML tidy can be a a handy tool to make your HTML "regexp'able". Brandoch Calef has made a Perl script that gets you most of the way. -
Document Revision # | -Action Taken, Notes | -When? | -By Whom? | -||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0.3 | -
+
| 12/24/2001 | Roberto Mello | ||||||||||||||||||||
0.2 | Changed recommendation from <phrase> to <emphasis role="strong"> | 01/19/2000 | Claus Rasmussen | ||||||||||||||||||||
0.1 | Creation | 12/2000 | Claus Rasmussen |
+
Constraint naming standard is important for one reason: The SYS_* name oracle assigns to unnamed constraints is not very understandable. By correctly naming all contraints, we can quickly associate a particular constraint with our data model. This gives us two real advantages: -
-We can quickly identify and fix any errors.
We can reliabily modify or drop constraints
-
We can quickly identify and fix any errors.
We can reliabily modify or drop constraints
+
Oracle limits names, in general, to 30 characters, which is hardly enough for a human readable constraint name. -
-We propose the following naming convention for all constraints, with the following abbreviations taken from Oracle Docs at http://oradoc.photo.net/ora81/DOC/server.815/a67779/ch4e.htm#8953. Note that we shortened all of the constraint abbrevations to two characters to save room. -
-Constraint type | -Abbreviation | -
---|---|
references (foreign key) | -fk | -
unique | -un | -
primary key | -pk | -
check | -ck | -
not null | -nn | -
+
Constraint type | Abbreviation |
---|---|
references (foreign key) | fk |
unique | un |
primary key | pk |
check | ck |
not null | nn |
<table name>_<column_name>_<constraint abbreviation> -
-+
In reality, this won't be possible because of the character limitation on names inside oracle. When the name is too long, we will follow these two steps in order: -
-Abbreviate the table name with the table's initials (e.g. users -> u and users_contact -> uc). -
Truncate the column name until it fits.
+
Abbreviate the table name with the table's initials (e.g. users -> u and users_contact -> uc). +
Truncate the column name until it fits.
If the constraint name is still too long, you should consider rewriting your entire data model :) -
-Notes:
-If you have to abbreviate the table name for one of the constraints, abbreviate it for all the constraints
If you are defining a multi column constraint, try to truncate the two column names evenly
+Notes:
If you have to abbreviate the table name for one of the constraints, abbreviate it for all the constraints
If you are defining a multi column constraint, try to truncate the two column names evenly
create table example_topics ( topic_id integer constraint example_topics_topic_id_pk @@ -142,17 +52,11 @@ constraint cne_example_id_one_line_unq unique(example_id, one_line_description) ); --
Naming primary keys might not have any obvious advantages. However, here's an example where naming the primary key really helps (and this is by no means a rare case! -
-+SQL> set autotrace traceonly explain; @@ -166,53 +70,18 @@ 2 1 TABLE ACCESS (FULL) OF 'CONSTRAINT_NAMING_EXAMPLE' 3 1 INDEX (UNIQUE SCAN) OF 'EXAMPLE_TOPICS_TOPIC_ID_PK' (UNI QUE) --+
Isn't it nice to see "EXAMPLE_TOPICS_TOPIC_ID_PK" in the trace and know exactly which table oracle is using at each step? -
-ArsDigita is split on whether or not we should be naming not null constraints... So, if you want to name them, please do so and follow the above naming standard. But, naming not null constraints is not a requirement at ArsDigita. -
--
+
+
+
Though naming "not null" constraints doesn't help immeditately in error debugging (e.g. the error will say something like "Cannot insert null value into column"), we recommend naming not null constraints to be consistent in our naming of all constraints. -
-+
To ensure consistency (and its collateral benefit, maintainability), we define and adhere to standards in the following areas: -
-+
Usually we organize our files so that they mainly serve one of the following three purposes: -
-displaying objects and their properties
manipulating or acting on objects in some way (by creating, editing, linking, etc)
housing procedures, packages, data models and other prerequisite code -Essentially, we want our files named in a fashion that reflects their purpose.
+
displaying objects and their properties
manipulating or acting on objects in some way (by creating, editing, linking, etc)
housing procedures, packages, data models and other prerequisite code +Essentially, we want our files named in a fashion that reflects their purpose.
Under the page root (and the template root if using the Style package): -
-For naming files that enable a specific action on an object, use this format:
---object-verb.extension -
+
For naming files that enable a specific action on an object, use this format:
+object-verb.extension +
For example, the page to erase a user's portrait from the database is /admin/users/portrait-erase.tcl. -
-However, modules typically deal with only one primary type of object - +
However, modules typically deal with only one primary type of object - e.g., the Bookmarks module deals mainly with bookmarks - and so action-type files in modules don't need to be specified by the object they act on. Example: the user pages for the Bookmarks module live in the /bookmarks/ directory, and so there is no need to name the bookmark editing page with a redundant url: /bookmarks/bookmark-edit.tcl. Instead, we omit the object type, and use this convention: -
---verb.extension -
+
+verb.extension +
Thus, the page to edit a bookmark is /bookmarks/edit.tcl. -
-For naming files that display the properties of a primary object - such as the bookmark object within the bookmark module - use this convention:
---one.extension -
+
For naming files that display the properties of a primary object - such as the bookmark object within the bookmark module - use this convention:
+one.extension +
For example, the page to view one bookmark is /bookmarks/one.tcl. Note that no verb is necessary for display-type files. -
-Otherwise, if the object to be displayed is not the primary feature of a module, simply omit the verb and use the object name:
---object.extension -
+
Otherwise, if the object to be displayed is not the primary feature of a module, simply omit the verb and use the object name:
+object.extension +
For example, the page to view the properties of an ecommerce product is /ecommerce/product.tcl. -
-For naming files in a page flow, use the convention:
--foobar.extension (Step 1)
-foobar-2.extension (Step 2)
...
-foobar-N.extension (Step N)
-where foobar is determined by the above +
For naming files in a page flow, use the convention:
foobar.extension (Step 1)
foobar-2.extension (Step 2)
...
foobar-N.extension (Step N)
+where foobar is determined by the above rules. -
-+
Typically, we use a three-step page flow when taking user information: -
-Present a form to the user
Present a confirmation page to the user
Perform the database transaction, then redirect
Put data model files in /www/doc/sql, and name them +
Present a form to the user
Present a confirmation page to the user
Perform the database transaction, then redirect
Put data model files in /www/doc/sql, and name them for the modules towards which they are used: -
---module.sql -
+
+module.sql +
In the Tcl library directory: -
-For files that contain module-specific procedures, use the -convention:
---module-procs.tcl -
For files that contain procedures that are part of the core ACS, -use the convention:
---ad-description-procs.tcl -
-File names also appear within pages, as linked URLs and +
For files that contain module-specific procedures, use the +convention:
+module-procs.tcl +
For files that contain procedures that are part of the core ACS, +use the convention:
+ad-description-procs.tcl +
+File names also appear within pages, as linked URLs and form targets. When they do, always use abstract URLs (e.g., user-delete instead of user-delete.tcl), because they enhance maintainability. -
-+
Similarly, when linking to the index page of a directory, do not explicitly name the index file (index.tcl, index.adp, index.html, etc.). Instead, use @@ -164,56 +68,40 @@ (/top-level-dir/). If linking to the directory in which the page is located, use the empty string (""), which browsers will resolve correctly. -
-Include the appropriate standard header in all scripts. The first line should be a comment specifying the file path relative to the ACS root directory. e.g. -
-+
-# /www/index.tcl -
+
or -
-+
-# /tcl/module-defs.tcl -
+
For static content files (html or adp), include a CVS identification tag as a comment at the top of the file, e.g. -
-+<!-- file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp --> --+
In addition, all static HTML files, documentation and other pages should have a visible CVS ID stamp, at least during development. These can be removed at release times. This should take the form of a line like this: -
-+<p> Last Modified: file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp </p> --+
This can be at the top or bottom of the file. -
-+
For non-library Tcl files (those not in the private Tcl directory), use ad_page_contract after the file path comment (this supersedes set_the_usual_form_variables and ad_return_complaint). Here is an example of using ad_page_contract, which serves both documentation and page input validation purposes: -
-+# www/register/user-login-2.tcl ad_page_contract { @@ -231,47 +119,35 @@ {return_url {[ad_pvt_home]}} {persistent_cookie_p f} } --+
Salient features of ad_page_contract: -
-A mandatory documentation string is the first argument. This has -the standard form with javadoc-style @author, @cvs-id, etc, and should contain a short description of the recieved variables and any necessary explanations.
The second argument specifies the page +
A mandatory documentation string is the first argument. This has +the standard form with javadoc-style @author, @cvs-id, etc, and should contain a short description of the recieved variables and any necessary explanations.
The second argument specifies the page inputs. The syntax for switches/flags (e.g. multiple-list, array, etc.) uses a colon (:) followed by any number of flags separated by commas (,), e.g. foo:integer,multiple,trim. In particular, multiple and array are the flags that correspond to the old -ad_page_variables flags.
There are new flags: trim, notnull and +ad_page_variables flags.
There are new flags: trim, notnull and optional. They do what you'd expect; values will not be trimmed, unless you mark them for it; empty strings are valid input, unless you specify notnull; and a specified variable will be considered required, -unless you declare it optional.
-ad_page_contract can do validation for you: the flags integer +unless you declare it optional.
ad_page_contract can do validation for you: the flags integer and sql_identifier will make sure that the values supplied are integers/sql_identifiers. The integer flag will also trim leading zeros. Note that unless you specify notnull, both will accept the empty string. -
Note that ad_page_contract does not generate +
Note that ad_page_contract does not generate QQvariables, which were automatically created by ad_page_variables and set_the_usual_form_variables. The use of bind variables makes such previous variable syntax obsolete. -
+
For shared Tcl library files, use ad_library after the file path comment. Its only argument is a doc_string in the standard (javadoc-style) format, like ad_page_contract. Don't forget to put the @cvs-id in there. Here is an example of using ad_library: -
-+# tcl/wp-defs.tcl ad_library { @@ -280,43 +156,32 @@ @author John Doe (jdoe@arsdigita.com) @cvs-id file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp } --Non-Tcl Files-+
For SQL and other non-Tcl source files, the following file header structure is recommended: -
---- path relative to the ACS root directory ++-- path relative to the ACS root directory -- --- brief description of the file's purpose +-- brief description of the file's purpose -- --- author --- created +-- author +-- created -- -- $Id$ --+
Of course, replace "--" with the comment delimiter appropriate for the language in which you are programming. -
-Construct the page as one Tcl variable (name it page_content), and then send it back to the browser with one call to doc_return, which will call db_release_unused_handles prior to executing ns_return, effectively combining the two operations. -
-+
For example: -
--set page_content "[ad_header "Page Title"] ++set page_content "[ad_header "Page Title"] -<h2>Page Title</h2> +<h2>Page Title</h2> <hr> @@ -327,16 +192,15 @@ select row_information from bar } { - append page_content "<li>row_information\n" + append page_content "<li>row_information\n" } append page_content "</ul> [ad_footer]" doc_return 200 text/html $page_content --+
The old convention was to call ReturnHeaders and then ns_write for each distinct chunk of the page. This approach has the disadvantage of tying up a scarce and valuable @@ -349,56 +213,22 @@ first, so that the user is not left to stare at an empty page while the query is running.) -
-+
Local procedures (i.e., procedures defined and used only within one -page) should be prefixed with "module_" and +page) should be prefixed with "module_" and should be used rarely, only when they are exceedingly useful. -
-+
All files that prepare HTML to display should end with [ad_footer] or -[module_footer]. If your module requires its own footer, +[module_footer]. If your module requires its own footer, this footer should call ad_footer within it. Why? Because when we adapt the ACS to a new site, it is often the case that the client will want a much fancier display than the ACS standard. We like to be able to edit ad_header (which quite possibly can start a <table>) and ad_footer (which may need to end the table started in ad_footer) to customize the look and feel of the entire site. -
-+
OpenACS version numbers help identify at a high-level what is in a particular release and what has changed since the last release. A "version number" is really just a string of the form: -
---major-minor-release -
-A change in the major version number indicates a fundamental +
major-minor-release
+A change in the major version number indicates a fundamental change in the architecture of the system, e.g. OpenACS 3 to ACS 4. A -change in the minor version number signifies the addition of +change in the minor version number signifies the addition of new modules and minor data model changes, e.g. OpenACS 3.1 to OpenACS 3.2. -The final release number indicates the relative maturity of a +The final release number indicates the relative maturity of a release and marks things like bug fixes; it follows the ordered progression: -
-+alpha beta 0 (production release) 1 2 ... --+
So typical release version numbers would be: -
-+openacs-3.2.5 openacs-4.0.beta --+
The first is a relatively mature release of the OpenACS 3.2 base code and the second is a non-public release of OpenACS 4.0 that probably still has lots of bugs. -
-+
Version numbers are also recorded in the CVS repository so that the code tree can be restored to the exact state it was in for a particular release. To translate between a distribution tar file (acs-3.2.2.tar.gz) and a CVS tag, just swap '.' for '-' and add the release date. The entire release history of the toolkit is recorded in the tags for the top-level readme.txt file: -
-+> cvs log readme.txt RCS file: /usr/local/cvsroot/acs/readme.txt,v Working file: readme.txt @@ -103,72 +69,28 @@ total revisions: 13; selected revisions: 13 description: ... --+
In the future, OpenACS packages should follow this same convention on version numbers. -
-So what distinguishes an alpha release from a beta +
So what distinguishes an alpha release from a beta release? Or from a production release? We follow a specific set of rules for how OpenACS makes the transition from one state of maturity to -the next.
-Every release must pass the minimum requirements that it cleanly +the next.
Every release must pass the minimum requirements that it cleanly installs and cleanly upgrades from the previous version of OpenACS. In -addition to this the release label implies:
--
- development -
-- -
This is the default state for the head of the current release branch. We -make no guarantees about this code.
- alpha -
-- -
All tickets of severity critical have been closed and the -distribution has no known installation or upgrade problems.
- beta -
-All tickets of severity serious or greater have been closed +addition to this the release label implies:
-
- development +
This is the default state for the head of the current release branch. We +make no guarantees about this code.
- alpha +
All tickets of severity critical have been closed and the +distribution has no known installation or upgrade problems.
- beta +
- -
All tickets of severity serious or greater have been closed and all documentation is up to date (version history, release notes, -new module docs, etc.).
- production [0, 1, ...] -
-- -
All tickets of severity medium or greater have been closed, -including issues reported from outside users.
In the future we will guarantee that more mature releases +new module docs, etc.).
- production [0, 1, ...] +
All tickets of severity medium or greater have been closed, +including issues reported from outside users.
In the future we will guarantee that more mature releases incorporate all the fixes for earlier problems by developing a detailed set of regression tests. For now we try to enforce this by restricting work on the release branch to fixing reported problem in the current release, e.g. no new features or big changes to -fundamental behavior.
-By You -
-
- NOTE: Some of the sections of this template may not apply to your
+ By You
+ NOTE: Some of the sections of this template may not apply to your
package, e.g. there may be no user-visible UI elements for a component
of the OpenACS Core. Furthermore, it may be easier in some circumstances
to join certain sections together, e.g. it may make sense to discuss
@@ -39,101 +9,50 @@
structure the design discussion by the structure used in the
requirements document. As this template is just a starting point, use
your own judgment, consult with peers when possible, and adapt
- intelligently.
-
- Also, bear in mind the audience for detailed design: fellow
+ intelligently.
+
+ Also, bear in mind the audience for detailed design: fellow
programmers who want to maintain/extend the software, AND parties
- interested in evaluating software quality.
-
When applicable, each of the following items should receive its own link:
- User directory OpenACS administrator directory Subsite administrator directory Tcl script directory (link to the API browser page for the package) PL/SQL file (link to the API browser page for the package) Data model Requirements document ER diagram Transaction flow diagram
+ User directory OpenACS administrator directory Subsite administrator directory Tcl script directory (link to the API browser page for the package) PL/SQL file (link to the API browser page for the package) Data model Requirements document ER diagram Transaction flow diagram
This section should provide an overview of the package
and address at least the following issues:
- What this package is intended to allow the user (or different
- classes of users) to accomplish. Within reasonable bounds, what this package is not intended to allow users to
- accomplish. The application domains where this package is most likely to be of use. A high-level overview of how the package meets its
+ What this package is intended to allow the user (or different
+ classes of users) to accomplish. Within reasonable bounds, what this package is not intended to allow users to
+ accomplish. The application domains where this package is most likely to be of use. A high-level overview of how the package meets its
requirements (which should have been documented elsewhere). This
is to include relevant material from the "features" section of the
cover sheet (the cover sheet is a wrapper doc with links to all
- other package docs).
+ other package docs).
Also worthy of treatment in this section:
- When applicable, a careful demarcation between the
+ When applicable, a careful demarcation between the
functionality of this package and others which - at least
- superficially - appear to address the same requirements.
+ superficially - appear to address the same requirements.
Note: it's entirely possible that a discussion of what a package
is not intended to do differs from a discussion of future
improvements for the package.
-
For a given set of requirements, typically many possible
implementations and solutions exist. Although eventually only one
solution is implemented, a discussion of the alternative solutions
canvassed - noting why they were rejected - proves helpful to both
current and future developers. All readers would be reminded as to
why and how the particular solution developed over time, avoiding
re-analysis of problems already solved.
-
Although currently only a few package documentation pages contain a
discussion of competing software, (e.g. chat, portals), this section
should be present whenever such competition exists.
- If your package exhibits features missing from competing
- software, this fact should be underscored. If your package lacks features which are present in competing
+ If your package exhibits features missing from competing
+ software, this fact should be underscored. If your package lacks features which are present in competing
software, the reasons for this should be discussed here; our sales
team needs to be ready for inquiries regarding features our software
- lacks.
+ lacks.
Note that such a discussion may differ from a discussion of a
package's potential future improvements.
-
No single design solution can optimize every desirable software
attribute. For example, an increase in the security of a system will
likely entail a decrease in its ease-of-use, and an increase in the
@@ -143,42 +62,16 @@
should include a discussion of the tradeoffs involved with the design
chosen, and the reasons for your choices. Some areas of importance to
keep in mind are:
- Areas of interest to users: Performance: availability and efficiency Flexibility Interoperability Reliability and robustness Usability Areas of interest to developers: Maintainability Portability Reusability Testability
+ Areas of interest to users: Performance: availability and efficiency Flexibility Interoperability Reliability and robustness Usability Areas of interest to developers: Maintainability Portability Reusability Testability
Here's where you discuss the abstractions used by your package, such
as the procedures encapsulating the legal transactions on the data
model. Explain the organization of procedures and their
particulars (detail above and beyond what is documented in the
code), including:
- Problem-domain components: key algorithms, e.g. a specialized
- statistics package would implement specific mathematical procedures. User-interface components: e.g. HTML widgets that the package may need. Data management components: procedures that provide a stable
+ Problem-domain components: key algorithms, e.g. a specialized
+ statistics package would implement specific mathematical procedures. User-interface components: e.g. HTML widgets that the package may need. Data management components: procedures that provide a stable
interface to database objects and legal transactions - the latter
- often correspond to tasks.
+ often correspond to tasks.
Remember that the correctness, completeness, and stability of the API
and interface are what experienced members of our audience are looking
for. This is a cultural shift for us at aD (as of mid-year 2000), in
@@ -187,183 +80,66 @@
handle transactions, instead of encapsulating them via procedures).
Experience has taught us that we need to focus on the API for
maintainability of our systems in the face of constant change.
-
+
Also noteworthy is that although the OpenACS currently utilizes the
AOLserver Tcl API, the current drive towards Java is likely to effect
a change in the content of these sections in the future.
-
The data model discussion should do more than merely display the SQL
code, since this information is already be available via a link in the
"essentials" section above. Instead, there should be a high-level
discussion of how your data model meets your solution requirements:
why the database entities were defined as they are, and what
transactions you expect to occur. (There may be some overlap with the
API section.) Here are some starting points:
- The data model discussion should address the intended usage
+ The data model discussion should address the intended usage
of each entity (table, trigger, view, procedure, etc.) when this
information is not obvious from an inspection of the data model
- itself. If a core service or other subsystem is being used (e.g., the
+ itself. If a core service or other subsystem is being used (e.g., the
new parties and groups, permissions, etc.) this should also be
- mentioned. Any default permissions should be identified herein. Discuss any data model extensions which tie into other
- packages. Transactions Discuss modifications which the database may undergo from
+ mentioned. Any default permissions should be identified herein. Discuss any data model extensions which tie into other
+ packages. Transactions Discuss modifications which the database may undergo from
your package. Consider grouping legal transactions according to
the invoking user class, i.e. transactions by an OpenACS-admin, by
- subsite-admin, by a user, by a developer, etc.
In this section, discuss user interface issues and pages to be built;
you can organize by the expected classes of users. These may include:
- Developers OpenACS administrators (previously known as site-wide administrators) Subsite administrators End users
+ Developers OpenACS administrators (previously known as site-wide administrators) Subsite administrators End users
You may want to include page mockups, site-maps, or other visual aids.
Ideally this section is informed by some prototyping you've done, to
establish the package's usability with the client and other interested
parties.
-
- Note: In order that developer documentation be uniform across
+
+ Note: In order that developer documentation be uniform across
different system documents, these users should herein be designated as
"the developer," "the OpenACS-admin," "the sub-admin," and "the user,"
- respectively.
-
+ respectively.
+
Finally, note that as our templating system becomes more entrenched
within the OpenACS, this section's details are likely to shift from UI
specifics to template interface specifics.
-
Under OpenACS 4.5, parameters are set at two levels: at the global level by
the OpenACS-admin, and at the subsite level by a sub-admin. In this
section, list and discuss both levels of parameters.
-
If the system presently lacks useful/desirable features, note details
here. You could also comment on non-functional improvements to the
package, such as usability.
-
+
Note that a careful treatment of the earlier "competitive analysis"
section can greatly facilitate the documenting of this section.
-
Although a system's data model file often contains this information,
this isn't always the case. Furthermore, data model files often
undergo substantial revision, making it difficult to track down the
system creator. An additional complication: package documentation may
be authored by people not directly involved in coding. Thus to avoid
unnecessary confusion, include email links to the following roles as
they may apply:
- System creator System owner Documentation author
- The revision history table below is for this template - modify it
- as needed for your actual design document.
-
+ The revision history table below is for this template - modify it
+ as needed for your actual design document.
+
-
-
-
-
-
-
-
-
-
-
-
-
-Document Revision #
-Action Taken, Notes
-When?
-By Whom?
-
-
-0.3
-Edited further, incorporated feedback from Michael Yoon
-9/05/2000
-Kai Wu
-
-
-0.2
-Edited
-8/22/2000
-Kai Wu
-
-
-
-0.1
-Creation
-8/21/2000
-Josh Finkler, Audrey McLoghlin
-Document Revision # Action Taken, Notes When? By Whom? 0.3 Edited further, incorporated feedback from Michael Yoon 9/05/2000 Kai Wu 0.2 Edited 8/22/2000 Kai Wu 0.1 Creation 8/21/2000 Josh Finkler, Audrey McLoghlin
High level information: What is OpenACS?
-Table of Contents
- -Table of Contents
- -User directory
Sitewide administrator directory
Subsite administrator directory
TCL script directory
Data model
PL/SQL file
- -ER diagram
Transaction flow diagram
Almost all database-backed websites have users, and need to model the +
User directory
Sitewide administrator directory
Subsite administrator directory
TCL script directory
Data model
PL/SQL file
ER diagram
Transaction flow diagram
Almost all database-backed websites have users, and need to model the grouping of users. The OpenACS 4 Parties and Groups system is intended to provide the flexibility needed to model complex real-world organizational structures, particularly to support powerful subsite services; that is, where one OpenACS installation can support what appears to the user as distinct web services -for different user communities.
-The primary limitation of the OpenACS 3.x user group system is that it +for different user communities.
The primary limitation of the OpenACS 3.x user group system is that it restricts the application developer to representing a "flat group" that contains only users: The user_groups table may contain the group_id of a parent group, but parent-child relationship support is limited because it only allows one kind of relationship between groups to be represented. Moreover, the Oracle database's limited support for tree-like structures makes the queries over these relationships -expensive.
-In addition, the Module Scoping design in OpenACS 3.0 introduced a -party abstraction - a thing that is a person or a group of people - +expensive.
In addition, the Module Scoping design in OpenACS 3.0 introduced a +party abstraction - a thing that is a person or a group of people - though not in the form of an explicit table. Rather, the triple of scope, user_id, and group_id columns was used to identify the party. One disadvantage of this design convention is that it increases a data model's complexity by requiring the programmer -to:
-add these three columns to each "scoped" table
define a multi-column check constraint to protect against data corruption +to:
add these three columns to each "scoped" table
define a multi-column check constraint to protect against data corruption (e.g., a row with a scope value of "group" but a null -group_id)
perform extra checks in Tcl and PL/SQL +group_id)
perform extra checks in Tcl and PL/SQL functions and procedures to check both the user_id and -group_id values
The core of the Group Systems data model is quite simple, but it was designed in the hopes of modeling "real world" organizations which can be complex graph structures. The Groups System only considers groups that can be modeled using directed acyclic graphs, but queries over these @@ -104,78 +35,48 @@ views, and auxiliary tables have been created in the hopes of increasing performance. To keep the triggers simple and the number of triggers small, the data model disallows updates on the membership and composition tables, -only inserts and deletes are permitted.
-The data model has tried to balance the need to model actual organizations +only inserts and deletes are permitted.
The data model has tried to balance the need to model actual organizations without making the system too complex or too slow. The added triggers, views, and tables and will increase storage requirements and the insert and delete times in an effort to speed access time. The limited flexibility (no updates -on membership) trades against the complexity of the code.
-The Group System data model consists of the following tables:
-The Group System data model consists of the following tables:
The set of all defined parties: any person, user, or -group must have a corresponding row in this table.
The set of all defined parties: any person, user, or +group must have a corresponding row in this table.
The set of all defined persons. To allow easy sorting of persons, the +
The set of all defined persons. To allow easy sorting of persons, the name requirement 30.10 is met by splitting the person's name into two columns: first_names and -last_name.
The set of all registered users; this table includes information about -the user's email address and the user's visits to the site.
The set of all registered users; this table includes information about +the user's email address and the user's visits to the site.
Preferences for the user.
Preferences for the user.
The set of all defined groups.
The set of all defined groups.
When a new type of group is created, this table holds additional -knowledge level attributes for the group and its subtypes.
When a new type of group is created, this table holds additional +knowledge level attributes for the group and its subtypes.
The set of direct membership relationships between a group and a -party.
The set of direct membership relationships between a group and a +party.
A mapping of a party P to the groups -{Gi}the party is a member of; this mapping +
A mapping of a party P to the groups +{Gi}the party is a member of; this mapping includes the type of relationship by including the appropriaterel_id -from the membership_rels table.
The set of direct component relationships between a group and another -group.
The set of direct component relationships between a group and another +group.
A mapping of a group Gto the set of groups -{Gi} that G is a component of; +
A mapping of a group Gto the set of groups +{Gi} that G is a component of; this mapping includes the type of relationship by including the -appropriaterel_id from the composition_rels table.
New groups are created through the group.new constructor. +appropriaterel_id from the composition_rels table.
New groups are created through the group.new constructor. When a specialized type of group is required, the group type can be extended by an application developer. Membership constraints can be specified at -creation time by passing a parent group to the constructor.
-The membership_rels and composition_rels tables indicate +creation time by passing a parent group to the constructor.
The membership_rels and composition_rels tables indicate a group's direct members and direct components; these tables do not provide a record of the members or components that are in the group by virtue of being a member or component of one of the group's component groups. @@ -186,104 +87,60 @@ paragraph) which watch for changes in membership or composition and update tables that maintain the group party mappings, i.e., group_member_index and group_component_index. One can think -of these tables as a manually maintained index.
-The following triggers keep the group_*_index tables up to -date:
-The following triggers keep the group_*_index tables up to +date:
Is executed when a new group/member relationship is created (an insert on -membership_rels)
Is executed when a new group/member relationship is created (an insert on +membership_rels)
Is executed when a group/member relationship is deleted (a delete on -membership_rels)
Is executed when a group/member relationship is deleted (a delete on +membership_rels)
Is executed when a new group/component relationship is created (an insert -on composition_rels)
Is executed when a new group/component relationship is created (an insert +on composition_rels)
Is executed when a group/component relationship is deleted (a delete on -composition_rels)
The data model provides the following views onto the +
Is executed when a group/component relationship is deleted (a delete on +composition_rels)
The data model provides the following views onto the group_member_index and group_component_index tables. No code outside of Groups System should modify the group_*_index -tables.
-A mapping of a party to the groups the party is a member of; this mapping +
A mapping of a party to the groups the party is a member of; this mapping includes the type of relationship by including the appropriaterel_id -from the membership_rels table.
A mapping of a party to the groups the party is an approved member of +
A mapping of a party to the groups the party is an approved member of (member_state is 'approved'); this mapping includes the type of relationship by including the appropriaterel_id from the -membership_rels table.
A person may appear in the group member map multiple times, for example, +
A person may appear in the group member map multiple times, for example, by being a member of two different groups that are both components of a third -group. This view is strictly a mapping of approved members -to groups.
A mapping of a group Gto the set of groups -{Gi} group G is a component of; +
A mapping of a group Gto the set of groups +{Gi} group G is a component of; this mapping includes the type of relationship by including the -appropriaterel_id from the composition_rels table.
A mapping of a party P to the set of parties -{Pi} party P is a member -of.
A mapping of a party P to the set of parties +{Pi} party P is a member +of.
A mapping of a party P to the set of parties -{Pi} party P is an -approved member of.
The API consists of tables and views and PL/SQL functions. -
-The group_types table is used to create new types of groups.
-The group_member_map, group_approved_member_map, +
The group_types table is used to create new types of groups.
The group_member_map, group_approved_member_map, group_distinct_member_map, group_component_map, party_member_map, and party_approved_member_map views are -used to query group membership and composition.
-Person
--person.new creates a new person and returns the +used to query group membership and composition.
Person
person.new creates a new person and returns the person_id. The function must be given the full name of the person in two pieces: first_names and last_name. All other fields are optional and default to null except for object_type which defaults to person and creation_date which defaults to sysdate. The -interface for this function is:
-+interface for this function is:function person.new ( person_id persons.person_id%TYPE, object_type acs_objects.object_type%TYPE, @@ -295,30 +152,20 @@ first_names persons.first_names%TYPE, last_name persons.last_name%TYPE ) return persons.person_id%TYPE; ---person.delete deletes the person whose person_id is -passed to it. The interface for this procedure is:
-+person.delete deletes the person whose person_id is +passed to it. The interface for this procedure is:
procedure person.delete ( person_id persons.person_id%TYPE ); ---person.name returns the name of the person whose -person_id is passed to it. The interface for this function is:
-+person.name returns the name of the person whose +person_id is passed to it. The interface for this function is:
function person.name ( person_id persons.person_id%TYPE ) return varchar; --User
--acs_user.new creates a new user and returns the user_id. +
User
acs_user.new creates a new user and returns the user_id. The function must be given the user's email address and the full name of the user in two pieces: first_names and last_name. All -other fields are optional. The interface for this function is:
-+other fields are optional. The interface for this function is:function acs_user.new ( user_id users.user_id%TYPE, object_type acs_objects.object_type%TYPE, @@ -336,45 +183,33 @@ screen_name users.screen_name%TYPE, email_verified_p users.email_verified_p%TYPE ) return users.user_id%TYPE; ---acs_user.delete deletes the user whose user_id is passed -to it. The interface for this procedure is:
-+acs_user.delete deletes the user whose user_id is passed +to it. The interface for this procedure is:
procedure acs_user.delete ( user_id users.user_id%TYPE ); ---acs_user.receives_alerts_p returns 't' if the user should +
acs_user.receives_alerts_p returns 't' if the user should receive email alerts and 'f' otherwise. The interface for this -function is:
-+function is:function acs_user.receives_alerts_p ( user_id users.user_id%TYPE ) return varchar; --Use the procedures acs_user.approve_email and +
Use the procedures acs_user.approve_email and acs_user.unapprove_email to specify whether the user's email -address is valid. The interface for these procedures are:
-+address is valid. The interface for these procedures are:procedure acs_user.approve_email ( user_id users.user_id%TYPE ); procedure acs_user.unapprove_email ( user_id users.user_id%TYPE ); --Group
--acs_group.new creates a new group and returns the +
Group
acs_group.new creates a new group and returns the group_id. All fields are optional and default to null except for object_type which defaults to 'group', creation_date which defaults to sysdate, and group_name which is required. The interface for -this function is:
-+this function is:function acs_group.new ( group_id groups.group_id%TYPE, object_type acs_objects.object_type%TYPE, @@ -385,32 +220,22 @@ url parties.url%TYPE, group_name groups.group_name%TYPE ) return groups.group_id%TYPE; ---acs_group.name returns the name of the group whose -group_id is passed to it. The interface for this function is:
-+acs_group.name returns the name of the group whose +group_id is passed to it. The interface for this function is:
function acs_group.name ( group_id groups.group_id%TYPE ) return varchar; ---acs_group.member_p returns 't' if the specified party is +
acs_group.member_p returns 't' if the specified party is a member of the specified group. Returns 'f' otherwise. The interface -for this function is:
-+for this function is:function acs_group.member_p ( group_id groups.group_id%TYPE, party_id parties.party_id%TYPE, ) return char; --Membership Relationship
--membership_rel.new creates a new membership relationship type +
Membership Relationship
membership_rel.new creates a new membership relationship type between two parties and returns the relationship type's rel_id. All fields are optional and default to null except for rel_type -which defaults to membership_rel. The interface for this function is:
-+which defaults to membership_rel. The interface for this function is:function membership_rel.new ( rel_id membership_rels.rel_id%TYPE, rel_type acs_rels.rel_type%TYPE, @@ -420,65 +245,43 @@ creation_user acs_objects.creation_user%TYPE, creation_ip acs_objects.creation_ip%TYPE, ) return membership_rels.rel_id%TYPE; ---membership_rel.ban sets the member_state of the given -rel_id to 'banned'. The interface for this procedure is:
-+membership_rel.ban sets the member_state of the given +rel_id to 'banned'. The interface for this procedure is:
procedure membership_rel.ban ( rel_id membership_rels.rel_id%TYPE ); ---membership_rel.approve sets the member_state of the +
membership_rel.approve sets the member_state of the given rel_id to 'approved'. The interface for this procedure -is:
-+is:procedure membership_rel.approve ( rel_id membership_rels.rel_id%TYPE ); ---membership_rel.reject sets the member_state of the given -rel_id to 'rejected. The interface for this procedure is:
-+membership_rel.reject sets the member_state of the given +rel_id to 'rejected. The interface for this procedure is:
procedure membership_rel.reject ( rel_id membership_rels.rel_id%TYPE ); ---membership_rel.unapprove sets the member_state of the +
membership_rel.unapprove sets the member_state of the given rel_id to an empty string ''. The interface for this -procedure is:
-+procedure is:procedure membership_rel.unapprove ( rel_id membership_rels.rel_id%TYPE ); ---membership_rel.deleted sets the member_state of the +
membership_rel.deleted sets the member_state of the given rel_id to 'deleted'. The interface for this procedure -is:
-+is:procedure membership_rel.deleted ( rel_id membership_rels.rel_id%TYPE ); ---membership_rel.delete deletes the given rel_id. The -interface for this procedure is:
-+membership_rel.delete deletes the given rel_id. The +interface for this procedure is:
procedure membership_rel.delete ( rel_id membership_rels.rel_id%TYPE ); --Composition Relationship
--composition_rel.new creates a new composition relationship type +
Composition Relationship
composition_rel.new creates a new composition relationship type and returns the relationship's rel_id. All fields are optional and default to null except for rel_type which defaults to -composition_rel. The interface for this function is:
-+composition_rel. The interface for this function is:function membership_rel.new ( rel_id composition_rels.rel_id%TYPE, rel_type acs_rels.rel_type%TYPE, @@ -487,117 +290,17 @@ creation_user acs_objects.creation_user%TYPE, creation_ip acs_objects.creation_ip%TYPE, ) return composition_rels.rel_id%TYPE; ---composition_rel.delete deletes the given rel_id. The -interface for this procedure is:
-+composition_rel.delete deletes the given rel_id. The +interface for this procedure is:
procedure membership_rel.delete ( rel_id composition_rels.rel_id%TYPE ); --
Document Revision # | -Action Taken, Notes | -When? | -By Whom? | -
0.1 | -Creation | -08/22/2000 | -Rafael H. Schloming | -
0.2 | -Initial Revision | -08/30/2000 | -Mark Thomas | -
0.3 | -Additional revisions; tried to clarify membership/compostion | -09/08/2000 | -Mark Thomas | -
Document Revision # | Action Taken, Notes | When? | By Whom? |
0.1 | Creation | 08/22/2000 | Rafael H. Schloming |
0.2 | Initial Revision | 08/30/2000 | Mark Thomas |
0.3 | Additional revisions; tried to clarify membership/compostion | 09/08/2000 | Mark Thomas |
Almost all database-backed websites have users, and need to model the +
Almost all database-backed websites have users, and need to model the grouping of users. The OpenACS 4 Parties and Groups system is intended to provide the flexibility needed to model complex real-world organizational structures, particularly to support powerful subsite services; that is, where one OpenACS installation can support what appears to the user as distinct web services -for different user communities.
-A powerful web service that can meet the needs of large enterprises must +for different user communities.
A powerful web service that can meet the needs of large enterprises must be able to model the the real world's very rich organizational structures and many ways of decomposing the same organization. For example, a corporation can be broken into structures (the corporation, its divisions, and their departments) or regions (the Boston office, the LA office); a person who is employed by (is a member of) a specific department is also a member of the division and the corporation, and works at (is a member of, but in a different sense) a particular office. OpenACS 4's Parties and Groups -system will support such complex relations faithfully.
-Historical Motivations
-The primary limitation of the OpenACS 3.x user group system is that it +system will support such complex relations faithfully.
Historical Motivations
The primary limitation of the OpenACS 3.x user group system is that it restricts the application developer to representing a "flat group" that contains only users: The user_groups table may contain the group_id of a parent group, but parent-child relationship support is limited because it only allows one kind of relationship between groups to be represented. Moreover, the Oracle database's limited support for tree-like structures makes the queries over these relationships -expensive.
-In addition, the Module Scoping design in OpenACS 3.0 introduced a -party abstraction - a thing that is a person or a group of people - +expensive.
In addition, the Module Scoping design in OpenACS 3.0 introduced a +party abstraction - a thing that is a person or a group of people - though not in the form of an explicit table. Rather, the triple of scope, user_id, and group_id columns was used to identify the party. One disadvantage of this design convention is that it increases a data model's complexity by requiring the programmer -to:
-add these three columns to each "scoped" table
define a multi-column check constraint to protect against data corruption +to:
add these three columns to each "scoped" table
define a multi-column check constraint to protect against data corruption (e.g., a row with a scope value of "group" but a null -group_id)
perform extra checks in Tcl and PL/SQL +group_id)
perform extra checks in Tcl and PL/SQL functions and procedures to check both the user_id and -group_id values
In sum, the goal of the Parties and Groups system is to +group_id values
In sum, the goal of the Parties and Groups system is to provide OpenACS programmers and site administrators with simple tools that fully describe the complex relationships that exist among groups in the real -world.
-Pat Developer has a client project and wants to model the company, its offices, its divisions, and its departments as groups and the employees as -users.
-We start with Groups, which contain members; the -member can be either a person or another group (i.e. a -member is a party).
-In addition to membership, the party and groups system defines a -composition relationship that may exist between groups: A -group can be a component of another group. The child group -is called a component group; the parent group is called a -composite group.
-A group Gc can be a member and/or a component -of another group Gp; the difference is in the way -the members of Gc are related to -Gp:
-If a party P is a member (or a component) of -Gc and if Gc is a -component of Gp, then P is also -a member (or a component) of Gp -
If a party P is a member (or a component) of -Gc and if Gc is a -member of Gp, then no -relationship between P and -Gp exists as a result of the relationship between -Gp and Gp.
Consider an example to make this less abstract: Pretend that the Sierra -Club is a member of Greenpeace. The Sierra Club has chapters; each -chapter is a component of the Sierra Club. If Eddie Environmentalist +users.
We start with Groups, which contain members; the +member can be either a person or another group (i.e. a +member is a party).
In addition to membership, the party and groups system defines a +composition relationship that may exist between groups: A +group can be a component of another group. The child group +is called a component group; the parent group is called a +composite group.
A group Gc can be a member and/or a component +of another group Gp; the difference is in the way +the members of Gc are related to +Gp:
If a party P is a member (or a component) of +Gc and if Gc is a +component of Gp, then P is also +a member (or a component) of Gp
If a party P is a member (or a component) of +Gc and if Gc is a +member of Gp, then no +relationship between P and +Gp exists as a result of the relationship between +Gp and Gp.
Consider an example to make this less abstract: Pretend that the Sierra +Club is a member of Greenpeace. The Sierra Club has chapters; each +chapter is a component of the Sierra Club. If Eddie Environmentalist is a member of the Massachusetts Chapter of the Sierra Club, Eddie is automatically a member of the Sierra Club, but being a Sierra Club member -does not make Eddie a member of Greenpeace.
-In the OpenACS, Greenpeace, Sierra Club, and the Sierra Club chapters would be +does not make Eddie a member of Greenpeace.
In the OpenACS, Greenpeace, Sierra Club, and the Sierra Club chapters would be modeled as groups, and Eddie would be a user. There would be a composition relationship between each Sierra Club chapter and the Sierra Club. Membership relationships would exist between Eddie and the Massachusetts Chapter, between Eddie and the Sierra Club (due to Eddie's membership in the -Massachusetts chapter), and between the Sierra Club and Greenpeace.
-Membership requirements can vary from group to group. The parties and +Massachusetts chapter), and between the Sierra Club and Greenpeace.
Membership requirements can vary from group to group. The parties and groups system must provide a base type that specifies the bare minimum -necessary to join a group.
-The parties and groups system must support constraints between a composite -group GP and any of its component groups, -GC. For example, the system should be able to -enforce a rule like: Do not allow a party P to become a -member of GC unless P is already -a member of GP.
-The data model for the parties and groups system must provide support for -the following types of entities:
-The parties and groups system must support constraints between a composite +group GP and any of its component groups, +GC. For example, the system should be able to +enforce a rule like: Do not allow a party P to become a +member of GC unless P is already +a member of GP.
The data model for the parties and groups system must provide support for +the following types of entities:
A party is an entity used to represent either a -group or a person.
-The data model should enforce these constraints:
--10.10 A party has an email address, which can be -empty.
--10.20 A party may have multiple email addresses -associated with it.
--10.30 The email address of a party must be unique within -an OpenACS system.
-A party is an entity used to represent either a +group or a person.
The data model should enforce these constraints:
10.10 A party has an email address, which can be +empty.
10.20 A party may have multiple email addresses +associated with it.
10.30 The email address of a party must be unique within +an OpenACS system.
A group is a collection of zero or more parties.
--20.10 The data model should support the subclassing of -groups via OpenACS Objects.
-A group is a collection of zero or more parties.
20.10 The data model should support the subclassing of +groups via OpenACS Objects.
A person represents an actual human being, past or -present.
- -A person represents an actual human being, past or +present.
A user is a person who has registered with an OpenACS site. A -user may have additional attributes, such as a screen name.
-The data model should enforce these constraints:
--40.10 A user must have a non-empty email address.
--40.20 Two different users may not have the same email +
A user is a person who has registered with an OpenACS site. A +user may have additional attributes, such as a screen name.
The data model should enforce these constraints:
40.10 A user must have a non-empty email address.
40.20 Two different users may not have the same email address on a single OpenACS installation; i.e., an email address identifies a -single user on the system.
--40.30 A user may have multiple email addresses; for -example, two or more email addresses may identify a single user.
--40.40 A user must have password field which can be -empty.
-The data model for the parties and groups system must provide support for -the following types of relationships between entities:
-40.30 A user may have multiple email addresses; for +example, two or more email addresses may identify a single user.
40.40 A user must have password field which can be +empty.
The data model for the parties and groups system must provide support for +the following types of relationships between entities:
-A party P is considered a member of a -group G -
-when a direct membership relationship exists between P -and G -
or when there exists a direct membership relationship between -P and some group GC and -GC has a composition relationship (c.f., 60.0) with G.
-50.10 A party may be a member of multiple groups.
--50.20 A party may be a member of the same group multiple +
+A party P is considered a member of a +group G
when a direct membership relationship exists between P +and G
or when there exists a direct membership relationship between +P and some group GC and +GC has a composition relationship (c.f., 60.0) with G.
50.10 A party may be a member of multiple groups.
50.20 A party may be a member of the same group multiple times only when all the memberships have different types; for example, Jane may be a member of The Company by being both an Employee and an -Executive.
--50.30 A party as a member of itself is not supported.
--50.40 The data model must support membership -constraints.
--50.50The data model should support the subclassing of -membership via OpenACS Relationships.
-50.30 A party as a member of itself is not supported.
50.40 The data model must support membership +constraints.
50.50The data model should support the subclassing of +membership via OpenACS Relationships.
A group GC is considered a -component of a second group -GP -
-when a direct composition relationship exists between -GC and GP -
or when there exists a direct composition relationship between -GC and some group Gi -and Gi has a composition relationship with -GP.
-60.10A group may be a component of multiple groups.
--60.20A group as a component of itself is not -supported.
--60.30The data model must support component -constraints.
--60.40The data model should support the subclassing of -composition via OpenACS Relationships.
-The API should let programmers accomplish the following tasks:
-A group GC is considered a +component of a second group +GP
when a direct composition relationship exists between +GC and GP
or when there exists a direct composition relationship between +GC and some group Gi +and Gi has a composition relationship with +GP.
60.10A group may be a component of multiple groups.
60.20A group as a component of itself is not +supported.
60.30The data model must support component +constraints.
60.40The data model should support the subclassing of +composition via OpenACS Relationships.
The API should let programmers accomplish the following tasks:
The parties and groups system provides a well defined API call that +
The parties and groups system provides a well defined API call that creates a new group by running the appropriate transactions on the parties and groups system data model. This API is subject to the constraints laid out -in the data model.
The parties and groups system provides a well defined API call that +
The parties and groups system provides a well defined API call that creates a new person by running the appropriate transactions on the parties and groups system data model. This API is subject to the constraints laid out -in the data model.
The parties and groups system provides a well defined API call that +
The parties and groups system provides a well defined API call that creates a new user by running the appropriate transactions on the parties and groups system data model. This API is subject to the constraints laid out in -the data model.
The parties and groups system provides a well defined API call that +
The parties and groups system provides a well defined API call that creates a new user by running the appropriate transactions on an existing person entity. This API is subject to the constraints laid out in the data -model.
The parties and groups system provides a well defined API call that +
The parties and groups system provides a well defined API call that demotes an existing user entity to a person entity by running the appropriate transactions on the existing user. This API is subject to the constraints -laid out in the data model.
The programmer should be able to modify, add, and delete attributes on any -party. This API is subject to the constraints laid out in the data model.
The programmer should be able to modify, add, and delete attributes on any +party. This API is subject to the constraints laid out in the data model.
The programmer should be able to view the attributes on any party. This -API is subject to the constraints laid out in the data model.
The programmer should be able to view the attributes on any party. This +API is subject to the constraints laid out in the data model.
The system provides an API for deleting a party. This API is subject to -the constraints laid out in the data model.
--100.30 The system may provide a single API call to remove -the party from all groups and then delete the party.
--100.40 In the case of a group, the system may provide a +
The system provides an API for deleting a party. This API is subject to +the constraints laid out in the data model.
100.30 The system may provide a single API call to remove +the party from all groups and then delete the party.
100.40 In the case of a group, the system may provide a single API call to remove all parties from a group and then delete the -group.
-The parties and groups system provides an API for adding a party as a +
The parties and groups system provides an API for adding a party as a member of a group. This API is subject to the constraints laid out in the -data model.
The parties and groups system provides an API for adding a group as a +
The parties and groups system provides an API for adding a group as a component of a second group. This API is subject to the constraints laid out -in the data model.
The parties and groups system provides an API for deleting a party's +
The parties and groups system provides an API for deleting a party's membership in a group. This API is subject to the constraints laid out in the -data model.
The parties and groups system provides an API for deleting a group's +
The parties and groups system provides an API for deleting a group's composition in a second group. This API is subject to the constraints laid -out in the data model.
The parties and groups system provides an API for answering the question: -"Is party P a member of group -G?"
The parties and groups system provides an API for answering the question: +"Is party P a member of group +G?"
The parties and groups system provides an API for answering the question: -"Is group GC a component of group -GP?"
The parties and groups system provides an API for answering the question: +"Is group GC a component of group +GP?"
The parties and groups system provides an API for answering the question: -"Which parties are members of group G?"
The parties and groups system provides an API for answering the question: +"Which parties are members of group G?"
The parties and groups system provides an API for answering the question: -"Which groups are components of group G?"
The parties and groups system provides an API for answering the question: +"Which groups are components of group G?"
The parties and groups system provides an API for answering the question: -"Of which groups is party P a member?"
The parties and groups system provides an API for answering the question: +"Of which groups is party P a member?"
The parties and groups system provides an API for answering the question: -"Of which groups is group G a component?"
The parties and groups system provides an API for answering the question: +"Of which groups is group G a component?"
The parties and groups system provides an API for answering the question: -"Is party P allowed to become a member of group -G?"
The parties and groups system provides an API for answering the question: +"Is party P allowed to become a member of group +G?"
The parties and groups system provides an API for answering the question: -"Is group GC allowed to become a component -of group GP?"
The parties and groups system provides an API for answering the question: +"Is group GC allowed to become a component +of group GP?"
Since many pages at a site may check membership in a group before serving +
Since many pages at a site may check membership in a group before serving a page (e.g., as part of a general permissions check), the data model must support the efficient storage and retrieval of party attributes and -membership.
Since many SQL queries will check membership in a group as part of the +
Since many SQL queries will check membership in a group as part of the where clause, whatever mechanism is used to check membership in SQL -should be fairly small and simple.
The user interface is a set of HTML pages that are used to drive the -underlying API. The user interface may provide the following functions:
--200.0 Create a party
-210.0 View the attributes of a party
-220.0 Update the attributes of a party
-240.0 Delete a party
-250.0 Add a party to a group
-260.0 Remove a party from a group
-270.0 Perform the membership and composition checks -outlined in 130.x to 165.x
Document Revision # | -Action Taken, Notes | -When? | -By Whom? | -
0.1 | -Creation | -08/16/2000 | -Rafael Schloming | -
0.2 | -Initial revision | -08/19/2000 | -Mark Thomas | -
0.3 | -Edited and reviewed, conforms to requirements template | -08/23/2000 | -Kai Wu | -
0.4 | -Further revised, added UI requirements | -08/24/2000 | -Mark Thomas | -
0.5 | -Final edits, pending freeze | -08/24/2000 | -Kai Wu | -
0.6 | -More revisions, added composition requirements | -08/30/2000 | -Mark Thomas | -
0.7 | -More revisions, added composition requirements | -09/08/2000 | -Mark Thomas | -
The user interface is a set of HTML pages that are used to drive the +underlying API. The user interface may provide the following functions:
200.0 Create a party
210.0 View the attributes of a party
220.0 Update the attributes of a party
240.0 Delete a party
250.0 Add a party to a group
260.0 Remove a party from a group
270.0 Perform the membership and composition checks +outlined in 130.x to 165.x
Document Revision # | Action Taken, Notes | When? | By Whom? |
0.1 | Creation | 08/16/2000 | Rafael Schloming |
0.2 | Initial revision | 08/19/2000 | Mark Thomas |
0.3 | Edited and reviewed, conforms to requirements template | 08/23/2000 | Kai Wu |
0.4 | Further revised, added UI requirements | 08/24/2000 | Mark Thomas |
0.5 | Final edits, pending freeze | 08/24/2000 | Kai Wu |
0.6 | More revisions, added composition requirements | 08/30/2000 | Mark Thomas |
0.7 | More revisions, added composition requirements | 09/08/2000 | Mark Thomas |
For Everyone - - OpenACS 4.5 beta Release Notes - - Older Release Notes + - OpenACS 4.5 Release Notes + - Older Release Notes For OpenACS-admins - Unix Installation Guide - Windows Installation Guide - - ACS Repository For Developers - Kernel Documentation @@ -45,9 +44,9 @@ Primers and References - AOLserver Documentation - (the Tcl Developer's Guide in particular.) - - Tcl for Web Nerds - - SQL for Web Nerds + (the Tcl Developer's Guide in particular.) + - Tcl for Web Nerds + - SQL for Web Nerds
Questions or comments about the documentation?
Please visit the
OpenACS bboards
-or shoot email at vinod@kurup.com or rmello at fslc.usu.edu.
+or shoot email at vinod@kurup.com or rmello at fslc.usu.edu.
Table of Contents
-Index: openacs.org-dev/packages/acs-core-docs/www/index.html =================================================================== RCS file: /usr/local/cvsroot/openacs.org-dev/packages/acs-core-docs/www/index.html,v diff -u -r1.1.1.1 -r1.1.1.2 --- openacs.org-dev/packages/acs-core-docs/www/index.html 9 Jul 2002 17:34:57 -0000 1.1.1.1 +++ openacs.org-dev/packages/acs-core-docs/www/index.html 11 Aug 2002 00:42:48 -0000 1.1.1.2 @@ -1,148 +1,4 @@ - -
- -
- - - - - -