|
||||||||||||||
|
|
|
|
|||||||||||
|
||||||||||||||
|
Home
|
![]() |
|
Acquisition Behavior
Unlike the notations for object relationships we have examined so far,
acquisition allows us to get to a given location using multiple paths.
And based on the path we follow, the value of the object will change. So
it is not an overstatement to say, "Acquisition is Different!"
Why Acquisition?Most common sense revolves around being able to evaluate the context of a question. If you are watching television and someone asks you, "What are you watching?" they expect you to tell them something about the show you are viewing, not respond with "a collection of small dots projected onto the front panel of a cathode ray tube." Even though your technical response may have been correct, it was not appropriate for the context of the question. Likewise, if you are in a business meeting and someone asks for your phone number, they expect to get your office phone number, not the number of the phone at your summer cottage.One programming methodology that was developed to handle the issue of context is called acquisition. One of the characteristics of acquisition is that objects "acquire" attributes only in the context of their environment. Of course, we have five senses and a pretty powerful brain for determining context. How does a software program determine context? In the case of object databases like Zope's ZODB, the environment
is defined by the path taken to get to the object. This is certainly
different than the inheritance and file system paths we examined in Object
Relationship Notation. In those cases, there was one and only one
path to get to an object. With acquistion, we are suggesting that there
are multiple ways to get to the same object. And, on top of that, we are
suggesting that the object will take on different attributes depending
on the path taken. (Wow!) So just how does this acquisition thing work?
Acquired BehaviorFirst of all, we have to keep in mind that acquisition tries to answer the question, "What is the proper response in the context of what is already known?" In an inheritance path, there is only one way to reach an instance, so context is irrelevant. But with acquisition, we have to keep track of what we already know to understand the current context.So if I ask, "What do you want to drink?" you might respond with "Give me a soda." But if I say, "You're stranded in the middle of a winter blizzard. What do you want to drink?" you would probably change your response to "hot chocolate" or "hot coffee." If I pester you again and say, "You're stranded in a winter blizzard. But you're stranded inside a log cabin with a roaring fire. What do you want to drink?" you might change your answer back to "a soda." In answering my final query you had to evaluate two pieces of information before responding. First, you had to examine the possible ramifications of being in a blizzard. Then you had to judge what the tradeoffs might be if you were weathering the blizzard inside a warm cabin. You couldn't intelligently respond until you had considered each bit of information in order. This is the way that acquisition works in Zope. Introductory texts to Zope typically suggest that when a URL request
is handled, the ZPublisher module converts the request into a object database
path, and that the specified object is then rendered. While this interpretation
works for simple cases, it is not entirely accurate. Using acquisition,
the URL path defines the context in which the target object should be
interpreted. So for our previous example, we could define an object
named drink (for the time being, it doesn't matter where drink
is located) that could be reached with either
http://www.mydomain.com/blizzard/warm_cabin/drink http://www.mydomain.com/blizzard/abandoned_highway/drinkand we would get back two completely different answers, as the context (path) of the two requests are completely different. A Contrast in ConventionJust to make sure you don't get too confused, let me assure you that "Acquisition is different!" The way that acquisition uses a path is entirely different from virtually every other convention that you may have come across. In an inheritance path, for example, the search for an attribute
begins with the rightmost object and proceeds to the left. So in the path
vehicle.car.passenger_car.my_chevy_cavalier.start()we would look for the method start() first in the instance my_chevy_cavalier and start working our way to the left. This is the way that most tree structures are traversed. With acquistion, however, we have to evaluate the context in the order given. This means that we have to evaluate the URL path from left to right. So for our URL request of http://www.mydomain.com/blizzard/warm_cabin/drinkwe would start by looking for attributes needed to evaluate drink within the object blizzard. Then, we would look for the attributes needed to evaluate drink in the object warm_cabin, in the context of already knowing about blizzard. Confused? Perhaps an example will make the unique convention of acquisition a bit more clear. An ExampleLet's say that drink is a method in the blizzard folder that will print out the drink of choice. Let us also assume that blizzard is a top level folder that has a property drinkChoice with a value of "Hot Coffee," and that warm_cabin is another top-level folder with a value of "Cola" for its property drinkChoice. To give us another option, let's create a third top-level folder named abandoned_highway. This folder has a drinkChoice value of "Hot Chocolate." Finally, let's add a folder titled middle_of_nowhere that does not define drinkChoice.Remember now, our four folders are at the same level in our object database. So the URL request no longer has anything to do with the structure of objects in the database. We are now providing the Zope Object Request Broker (ZORB) with contextual information for our request. So when we issue a URL request of http://www.mydomain.com/blizzard/warm_cabin/drinkZope evaluates it in the following fashion: First, it says "Okay, we are asked to assume there is a blizzard going on. Do we have a blizzard object in the object database?" When it discovers that the blizzard object does exist, it then asks, "Given that we know about the blizzard object, do we know anything about being in a warm cabin?" Since the warm_cabin folder is at top level of the database, it is not contained in the blizzard folder, and it would be found whether we knew about the blizzard object or not. Now that the warm_cabin object has been found, it asks "Do we know anything about an attribute named drink?" Since our first contextual assumption was that a blizzard was occurring, we look first in the blizzard object. Indeed, we find a drink method inside the blizzard folder. After finding drink inside the blizzard folder, we would next look for it inside the warm_cabin folder, since we are looking for drink in the context of both blizzard and warm_cabin. If there were a drink method inside the warm_cabin folder, we would use that method since it is more specific in terms the environment described to us in the URL path. We always start with the information given to us with the most general context (in this case, blizzard), then keep updating our data with more specific contextual information (from warm_cabin). However, there is no drink method inside of warm_cabin, so we use the drink method from blizzard. It is now time to evaluate the drink method, which simply
prints out the value of property drinkChoice. Since a value for
drinkChoice is needed, Zope looks first in the blizzard
object, as that was the first contextual clue given by the URL request.
It finds a value of "Hot Coffee" for drinkChoice inside of blizzard.
But it does not stop there. It knows that there is additional contextual
information. So it next goes looking inside of warm_cabin to see
if there is additional information about property drinkChoice.
And warm_cabin says that drinkChoice should be "Cola."
So Zope say to itself, "Object warm_cabin is overriding some information
found in object blizzard, but since we were asked to assume a
warm_cabin in the context of a blizzard, the value of
drinkChoice must be "Cola." And therefore, method drink
prints out a request for cola.
What if we change the request to http://www.mydomain.com/warm_cabin/blizzard/drink?We have switched the positions of our request for warm_cabin and blizzard. This would obviously never work for a object database or file system. But this is the world of ACQUISITION! With acquisition, we will now evaluate blizzard in the context of warm_cabin. The value for drinkChoice inside blizzard is now considered more specific contextual data, and method drink prints out a request for "Hot Coffee." See what happened? Method drink was found in the context of blizzard in the context of warm_cabin. And when drink needed a value for drinkChoice, it looked first in the most general contextual object, warm_cabin, then it looked in the more specific contextual object, blizzard. Thus, method drink used the blizzard value for drinkChoice as being the most specific to the environment expressed by the URL path. What happens if our request is
http://www.mydomain.com/warm_cabin/drink?We get an error message! Why? Well, in the context of warm_cabin alone, we don't know anything about the method drink, which is contained inside blizzard. Therefore, in any URL request in which we want to evaluate drink, a reference to blizzard must come first. What about
http://www.mydomain.com/blizzard/drink? ![]() Since drink is known in the context of blizzard, a "Hot Coffee" is requested. You might note that if you're only referencing one object at each folder level in a acquisition path, it acts just like a file system path. What about being stuck along the highway? If we issue a URL request
of
http://www.mydomain.com/blizzard/abandoned_highway/drinkwe get a message asking for "Hot Chocolate." Okay, let's say we can't make up our minds right away. Let's issue a request of .../blizzard/abandoned_highway/warm_cabin/abandoned_highway/warm_cabin/drink
If this were a file system or object database path, we would surely get an error message. You just can't do this with normal object pathnames. Remember, though, "Acquisition is different!" In the above example, we are simply giving contextual information to the object broker to evaluate our drink request in terms of the specified environment. So Zope first gets drinkChoice information from blizzard, then abandoned_highway, then warm_cabin, then abandoned_highway again, then finally warm_cabin. So the drink method issues a request for "Cola." As a test of your growing knowledge of acquisition, what would
happen if we issued the following request?
http://www.mydomain.com/blizzard/middle_of_nowhere/drinkThat's right. The object middle_of_nowhere has no additional information about drinkChoice, so drink prints out the drinkChoice information it found in blizzard. Okay, one more example. If we add a method cozy_chair inside
of the folder warm_cabin, which of the following URL requests
are valid?
http://www.mydomain.com/blizzard/cozy_chair http://www.mydomain.com/blizzard/warm_cabin/cozy_chair http://www.mydomain.com/warm_cabin/blizzard/cozy_chairRight again. The URL path http://www.mydomain.com/blizzard/cozy_chair is invalid, because if we only know about the blizzard object, there is no way we can know about the cozy_chair object that is defined inside of warm_cabin. However, the the other two URL paths are valid because they both give us the contextual clue of warm_cabin prior to asking for cozy_chair. Therefore, we know where to find the method cozy_chair. If I've done my job, you now have a better understanding of how acquisition behaves in Zope. But, you may ask, why is it there in the first place? Well, read on, oh seeker of Zope Zen. The next section is "A Case for Acquisition". [ed. Now in development...
|
Search zopeNewbies: Search zopeNewbies 2: |
|||||||||
|
![]() Last update: Monday, March 27, 2000 at 5:13:16 AM Pacific. |