Using ACS service contracts

Using acs-service-contract

acs-service-contract is a package that "allows different packages to communicate via defined contracts". Essential, it defines an interface so that different packages can communicate with each other in a structured way.

Understanding how service contracts work

The best guide I've found on service contracts is Benjamin Bytheway's intro to service contracts. It currently uses the pl/pgsql API, instead of the newer Tcl API. However, this will give you an idea of what is going on, so that you can figure out the Tcl API. More information on the Tcl API is found here

Creating your service contract

Benjamin's tutorial describes using the pl/pgsql API. This would be defined in your .sql files, and instantiated when the package was initially installed by the APM. This would be easy enough, but we want to use the Tcl API, for two reasons: Where, then, do you define the workflow when using Tcl?

One of the features in OpenACS that have been added fairly recently has been the ability to have Tcl functions called before and after the install of your package. I believe this is probably the best way to do it.

So, you should look at install-procs.tcl file (and possibly the install-procs.xql and install-procs-postgresql.xql files). This is a little confusing, but I'll spell it out in more detail:

The install-procs.tcl file is looked at when the package is first installed (my guess is that the name is hard-coded in as something for the APM to look at). There are several procedures that if defined are called at specified times. These are package_install, package_uninstall, package_upgrade, package_instantiate, and package_uninstantiate. There may be others as well. I haven't found any documentation for this, but I looked at the bug-tracker and gleaned this from there.

Here is an example of a service contract (stolen from bug-tracker):

...

ad_proc -private bug_tracker::install::package_install {} {
    Package installation callback proc
} {
    db_transaction {
        bug_tracker::install::register_implementations
        bug_tracker::bug::workflow_create
    }
}

ad_proc -private bug_tracker::install::package_uninstall {} {
    Package un-installation callback proc
} {
    db_transaction {
        bug_tracker::bug::workflow_delete
        bug_tracker::install::unregister_implementations
    }
}

ad_proc -private bug_tracker::install::package_instantiate {
    {-package_id:required}
} {
    Package instantiation callback proc
} {
    # Create the project
    bug_tracker::project_new $package_id

    bug_tracker::bug::instance_workflow_create -package_id $package_id
}

ad_proc -private bug_tracker::install::package_uninstantiate {
    {-package_id:required}
} {
    Package un-instantiation callback proc
} {

    bug_tracker::project_delete $package_id
    bug_tracker::bug::instance_workflow_delete -package_id $package_id

}

ad_proc -private bug_tracker::install::register_implementations {} {
    db_transaction {
        bug_tracker::install::register_format_log_title_impl
        ...
    }
}

ad_proc -private bug_tracker::install::register_format_log_title_impl {} {

    set spec {
        name "FormatLogTitle"
        aliases {
            GetObjectType bug_tracker::bug::object_type
            GetPrettyName bug_tracker::bug::format_log_title::pretty_name
            GetTitle      bug_tracker::bug::format_log_title::format_log_title
        }
    }
    
    lappend spec contract_name [workflow::service_contract::activity_log_format_title]
    lappend spec owner [bug_tracker::package_key]
    
    acs_sc::impl::new_from_spec -spec $spec
}

ad_proc -private bug_tracker::install::unregister_implementations {} {
    db_transaction {

        acs_sc::impl::delete \
                -contract_name [workflow::service_contract::activity_log_format_title] \
                -impl_name "FormatLogTitle"

    ...
}


Reference