At the API level, a namespace program takes a string (the remaining part of the name to be resolved), a reference to a data stream (the input to the service the name represents), and a list of after-methods (the Active Names of services needed to transport the result of this service to its destination.) The namespace program first determines which namespace program to call next by partially evaluating a name and then delegating further resolution to a sub-namespace or--if the namespace is a leaf and the name is fully resolved--by popping the top after-method from the after methods list.
Then, if the program wants additional work to be done with the result of the call, it adds the corresponding after-methods to the after methods list.
Finally, the program calls the next program with the partially resolved name, the remaining list of after-methods, and a data stream that comes from either i) passing the incoming data stream to the next program unchanged, ii) creating a new data stream by filtering the incoming data stream, or iii) creating a new data stream from local state (e.g., by reading data from a cache).
To be practical, our Active Names architecture must be able to be smoothly integrated with legacy clients, servers, and name databases. We accomplish this by using either a library or a proxy that provides default translations between legacy names and corresponding Active Names. For example, we provide a web proxy that allows unmodified browsers to use the Active Names system.