I'm getting bored of trying to explain how shared data and inheritance work in ACAP, and how to use them, especially when on IRC, or trying not to bore people on mailing lists. So here's a quick explanation, so I don't keep repeating myself, and missing out bits each time.
I'll explain this in terms of the bookmarks dataset, as a typical example of a shared resource across multiple interested parties, and the Eudora autoconfig dataset, as a typical example of a configuration dataset.
This works best for shared resources, and doesn't work very usefully for configuration. The best analogy is a shared file, accessable by multiple users.
The administrator defines a shared dataset, say /bookmarks/group/shared/ - note that we use a group here, since ACAP doesn't allow for datasets to be arbitrarily named. Each user then gets a subdataset pointer somewhere in their personal datasets pointing to it, or else the administrator simply tells them about it.
The client application then picks up this data and uses it, typically in a read-only manner.
/bookmarks/~/shared
bookmarks.Type: "folder"
bookmarks.Name: "Developer resources"
bookmarks.Description: "Shared folder for bookmarks useful to developers"
subdataset: ("/bookmarks/group/shared/")
/bookmarks/group/shared/aaaaaa
bookmarks.Type: "link"
bookmarks.URL: "http://www.ietf.org/"
bookmarks.Name: "IETF"
bookmarks.Description: "Internet Engineering Task Force"
The client should present this in the bookmarks folder as something vaguely like:
| Bookmarks | |
| Developer resources => | IETF |
The user therefore sees a bunch of bookmarks, some of which happen to be shared - semantically, there's no difference, although the user may not be able to store useful metadata about the bookmark usage, and may not be able to edit the shared bookmarks.
This works for either shared resources or configuration, and it's pretty well a unique feature of ACAP. Or is it? No, not really - we've been used to /etc/somethingrc and ~/.somethingrc files for some time, and the semantics are pretty similar. The main difference is that for the client, the inheritance is transparent, and the client simply sees a bunch of datasets.
The general concept is this: The administrator sets up the same shared dataset as above, possibly this time using the "site" owner part. Each user's personal dataset then inherits from this one - unless the user specifically changes attributes in this dataset, they'll be the same as the shared dataset, now. Moreover, the user can always reset the attributes and indeed whole entries back to the defaults.
The administrator can prevent the user from changing all or part of an entry via ACLs, but even if the user does, it won't affect the shared dataset, only their "view" of the data.
/bookmarks/~/shared/
dataset.inherit: "/bookmarks/group/shared/"
/bookmarks/group/shared/
dataset.acl.entry: ("anyone\trx" "sharedadmin\trwixa")
dataset.acl.bookmarks.Visited: ("$owner\trxwai")
dataset.acl.bookmarks.Description: ("$owner\trwixa")
// And ACLs for the other metadata.
/bookmarks/group/shared/aaaaaa
// As above
The client should present this in exactly the same way as above - so the user sees the same thing. In this case, however, the user can store their metadata, and even change the descriptions, but not the ordering, or the URLs and names themselves. Better? I think so.
We can't change the structure - ACAP simply doesn't quite manage that - and we can't change the ordering because of the Very Weird Rename Issue, which would otherwise cause you headaches.
It's even more interesting with configuration:
/vendor.eudora/site/settings vendor.eudora.ACAPServer: "acap.example.com" vendor.eudora.AccessMethod: "IMAP" vendor.eudora.DomainQualifier: "example.com" vendor.eudora.DSDefault: "LDAP" vendor.eudora.ExtraNicknamesDir: "\\MyServer\shareddir\nicknames\" vendor.eudora.LDAPServer: "ldap.example.com" vendor.eudora.MailServer: "imap.example.com" vendor.eudora.SMTPServer: "smtp.example.com" vendor.eudora.UseACAPServer: "1" /vendor.eudora/user/bob/ dataset.inherit: "/vendor.eudora/site/" /vendor.eudora/user/bob/settings vendor.eudora.ACAPUserID: "bob" vendor.eudora.MailName: "bob" vendor.eudora.ReturnAddress: "bob@example.com" vendor.eudora.RealName: "Bob User"
Take a look at how much of the configuration is now shared between all the users - only the settings which change per-user need to be in the user's own dataset. As usual, ACLs can prevent changes to data which we'd prefer the users not to change - be aware that client needn't honour these with local configuration, of course, but it's still useful.
Each method has its pros and cons.
Essentially, if you want all your users to be able to actively change the data that everyone else sees, you'll want to be using a shared dataset tactic - whereas if you want users to be able to change only their view of the data, you'll be wanting an inherited dataset somewhere.
If you want both, then you'll need a client which recognises which data to change "for everyone", and knows to issue the STORE on the inherited entry rather than the one its reading - this requires a bit more in the way of client "smarts" than is usual in ACAP clients, which generally wholly ignore inheritance.
Finally, there's one gotcha with the shared dataset approach - the obvious way to create the "pointer" folder entry in the user's personal dataset is to use inheritance. However, if you do, you'll find that the subdataset entry is rewritten, and the user ends up with a virtual dataset, which is effectively identical to an inherited dataset with no changes of its own.
I've written this quite quickly, and although I do hope to refine it with better examples, and clearer wording, I hope it's enough to get the point across, and explain some of the uses of ACAP's somewhat unique data inheritance features.