Forum OpenACS Q&A: How to get an instance url from a package key?

Given a package key, what is the package's relative url from the site
map?  The only function I can find to address this is
site_node_closest_ancestor_package_url, but it only works for a
package key that's in the same site map branch as the page that's
calling the function.  If I try to retrieve a url for a package in
another branch, I get a blank.
Collapse
Posted by Stephen . on
A package key does not uniquely identify a package instance. You can pick the closest ancestor, all instance URLs, a random one, or something else. It would be easier if you had the package_id...

I can get the package_id from the package_key, so that's no problem. But I can't find any function in site_node that will return a url. When I use site_node_closest_ancestor_package_url, it only looks in the current branch.

root/
|
-------foo/
|
|
-------bar/

As far as I can tell, if package foo is mounted at /foo, and package bar is mounted at /bar, and I run this code:

[site_node_closest_ancestor_package_url -package_key foo]
from the page /bar/testpage.tcl, I get back a null result. If I run the same code from /foo/testpage.tcl, I get back "/foo/".

What I'm trying to do is write code for a package which will be run by the aa-test package, from the context of aa-test. So, given a package_key, I just want to know if it's installed, if it's mounted, and what its url is. If it's mounted more than once, I don't really care which one I get (though maybe I should, so that a test can be directed at a specific mount - but aren't all the mounts pointing to the same thing?).

Strictly speaking, a testcase shouldn't/cannot rely on a package actually already having been mounted. It's probably also not ideal to be running tests on a live package either. If a package testcase requires that the package be mounted, then I think its the testcase's responsibility to perform the package mount/unmount.

This is obviously not ideal, as its going to slow down the execution time of all the tests that need to so it. Particularly in the current situation where a testcase should clear all its own data up. One can imagine a set of say, 20 testcases for a package, each testcase having to do its own mount/unmount. Nasty.....

My suggestion would be that a testcase could belong to a "init_class", where an init_class indicates that a chunk of code should be run before and after a complete set of testcases is run. This essentially allows testcases to share initialisation/cleardown code. This slightly breaks the notion of a testcase clearing up its own data, but should enforce that everything does get cleared up by the aa-test package after running a set of testcases.

Cheers,

Collapse
Posted by Stephen . on
I can get the package_id from the package_key, so that's no problem.

You might get duplicates:

SQL> select package_id, package_key, instance_name from apm_packages order by package_key;

PACKAGE_ID PACKAGE_KEY                    INSTANCE_NAME
---------- ------------------------------ ------------------------------
       209 acs-admin                      ACS Administration
       241 acs-api-browser                ACS API Browser
       251 acs-content                    ACS Content
	1113 acs-content-repository         ACS Content Repository
       741 acs-core-docs                  ACS Core Documents
       765 acs-datetime                   ACS DateTime
      1512 acs-developer-support          Developer Support
        96 acs-kernel                     ACS Kernel
	780 acs-mail                       ACS Mail
      1133 acs-messaging                  ACS Messaging
	789 acs-notification               ACS Notification
      1479 acs-subsite                    Main Site
     13050 acs-subsite                    Bar
     13003 acs-subsite                    Foo Site
       333 acs-tcl                        ACS Tcl
       633 acs-templating                 ACS Templating
	 644 acs-util                       ACS Utilities
	1020 acs-workflow                   ACS Workflow
	2050 simple-survey                  Survey
	1478 skin                           Skin

20 rows selected.

I can't find any function in site_node that will return a url.

SQL> select node_id, object_id, name from site_nodes;

   NODE_ID  OBJECT_ID NAME
---------- ---------- ------------------------------
      1504       1479
      1505        209 acs-admin
      1506        741 doc
      1507        241 api-doc
      1510       1512 ds
     13001      13003 foo
      2048       2050 survey
     13034        241 api
     13048      13050 bar
     13086            empty-folder

10 rows selected.


SQL> select site_node.url(node_id) from site_nodes;

SITE_NODE.URL(NODE_ID)
----------------------
/
/acs-admin/
/doc/
/api-doc/
/ds/
/survey/
/foo/
/foo/api/
/bar/
/foo/empty-folder/

10 rows selected.

The object_id in site_nodes is a package_id. You can join against apm_packages to get the URLs of the packages you're interested in, given a package key:

SQL> select p.package_id, site_node.url(n.node_id)
     from site_nodes n, apm_packages p
     where n.object_id = p.package_id
     and p.package_key = 'acs-subsite';
  2    3    4
PACKAGE_ID site_node.url(n.node_id)
---------- ------------------------------
      1479 /
     13003 /foo/
     13050 /bar/

Aren't all the mounts pointing to the same thing?

For your purposes (I'm guessing) no. The testing you want to do will be agianst the database, and you'll need some data, and you'll need to distinguish it from other data. For that you need the package_id. Think of the package_id as an instance_id, it is unique for each mounted instance of a package, and distinguishes one mouonted packages data from another's.

Ok, to make sure I understand:  When I install a package on my site, it's identified by a package key.  When I choose "new application" in the site map, I'm creating an instance of that package (with its own, unique package_id) and, simultaneously, mounting it.  A "package-aware" application should partition its data by package_id.  I can mount the application in several places, and all will point back to the same code and the same data slice.  If I create a new application with the same package, the applications will share code but not data.

Thanks for the db examples; I was hoping to use a function instead of writing new code to dig out basic information, but ah well.  I guess there isn't much perceived need to do this sort of thing?

So.  To address both of the previous posts at once:  IMHO, it should be possible to aim the test suite at any application - at any instance of a package.  Reasons:

1) The test suite, or at least a subset (maybe the 'smoke-test' portion, maybe a 'data-safe' category, should be reasonably safe to run on a live package, so that it can be used for diagnosis of problems.

2) The full test suite should be run on new applications to make sure that they work.

3) There might also be a version of the test suite that runs against functions, not pages.  It would be used for other types of testing, such as before the UI is built, or if a custom UI breaks the automated test.

Whenever possible, tests should go through the UI and use the full http_request/parse the results approach, because this is the most comprehensive testing and can catch the most errors.

Collapse
Posted by Stephen . on
Yes, you've got it.

Ah I see, makes sense now. I thought you were building some kind of utPLSQL package for Postgres, but you're planning to exercise the UI as well. Nice...

Collapse
Posted by Jerry Asher on
I reported this same problem, gosh about a year ago, with ACS 4.0.

At that time, what I pointed out was that the package system and procedural API is oriented towards mounted independent packages, but offered little support for packages that have a dependency on other packages, or might want to change their behavior if another package has been mounted.

As you said, you could have a package key, but couldn't precisely determine the url (or the proper instance) of the package without diving into the SQL. How then, can one package create redirects to another package or more precisely, to the right instance of the right package?

I felt then, that the SQL solution was overly complex, introduced unneccessary complexity and maintainance constraints into the code, and while it would work, it missed the point: to interoperate reliably, and easily, packages need a richer runtime exploration API.

I ask the current architects to look at this anew.

Collapse
Posted by Don Baccus on
Ok, to make sure I understand: When I install a package on my site, it's identified by a package key. When I choose "new application" in the site map, I'm creating an instance of that package (with its own, unique package_id) and, simultaneously, mounting it. A "package-aware" application should partition its data by package_id. I can mount the application in several places, and all will point back to the same code and the same data slice. If I create a new application with the same package, the applications will share code but not data.
Joel, you understand very well! Something similar to this wording ought to go on the main site map page or linked as "help" or something. I think a lot of misunderstanding would be avoided if it were.

Jerry ... service contracts are meant to provide a means for a package to announce itself available to fulfill the needs of another package. "package glue". We need more work and thought in this area to think about what it really means to glue packages together under subsites and all that but I think the basic concept's very promising.

Collapse
Posted by Stephen . on
Looking back at Jerry's old post I see that apm_package_id_from_key was created.
As you said, you could have a package key, but couldn't precisely determine the url (or the proper instance) of the package without diving into the SQL.
If the package you're interested in is not a singleton or service, or cannot be found with site_node_closest_ancestor_package* then the proper instance of a package is a tricky thing to define, or at least package specific, I think...
If the package you're interested in is not a singleton or service, or cannot be found with site_node_closest_ancestor_package* then the proper instance of a package is a tricky thing to define, or at least package specific, I think,...

I agree. What I thought then that I would like to see was some method in which packages and package instances can publish/make known certain attributes about themselves: the names of services they provide, perhaps just a unique id, perhaps the ids of their administrators, or their organizations, or ...? Structured in a property list, but perhaps unstructured beyond that: the name and value of the property might be left up to the package instance, and might be settable both in the package init as well as from the site map. That would enable packages to examine their where-abouts and enable administrators to bundle/config together various package instances. (Sigh, how many tenses are in this paragraph?)

Collapse
Posted by Stephen . on
I don't understand what you're saying, except for the last bit.
...enable administrators to bundle/config together various package instances.
The way I seem to be building sites is to create meta-packages that implement the new functionality, and which mount other packages within their URL branch for re-use.

In this case I know exactly where a bboard is and what it's package_id is, as my meta-package mounts it itself and stores away the details.

The only problem I was having was getting dependant packages mounted when my meta-package is mounted from the site map. I think I see the correct solution in apm_post_instantiation_tcl_proc_from_key, but I haven't tried that yet.

As for administrators bundling together packages, that sounds like the problem "How do i transfer my site map and parameter values from dev to production?". I thought someone was looking at that a while ago, Henry..? How about storing the site map in the file system with Apache style .htaccess files which describe which package should be mounted there, and any parameter values..?

My own view is that the package manager doesn't suit our needs. It is not important to package up individual applications into standalone distribution files (*.apm) so that they can be installed willy-nilly. In fact I think it's detremental to the goal of producing an *integrated* tool kit (you don't have to look far to see the wheel re-invention...)

The problems discussed in "How do you separate project customisations from improvements?" are faced by each of us, but we have no tools to help us manage the complexity. A FreeBSD style system using CVS rather than the RedHat style package system we have would be more appropriate.

Anyway... If I wait long enough maybe Don will do it all for me.

It's been almost a year, but what I had in mind at a time, was the problem of one package needing to create redirections to another package, in the case where the targeted package might not be a singleton.

So your package wants to include redirects to adserver or clickthrough or all sorts of things that may not be mounted relative to your package.  If the target is not a singleton, and if the context isn't specified by user_id or something similar, how can anything determine the proper URL.

I don't know if this has been solved or not.  I solved it in the limited case of the adserver as the adserver was a singleton.  But I can certainly imagine cases when the adserver is not a singleton, you want different ads (and maybe different adserver instances) depending on the subsite, or gender, or zip code, or time of day, referrer_url, shopping cart contents, ....  What sort of things can be done by the implementor to address this?