\chapter{Defining and Assembling Components with \module{peak.binding}} \section{Component-Based Applications} What's in a component, anyway? Why use them to develop software? Software developers have dreamed for decades of a future where applications could be built by simply plugging together off-the-shelf components. In some development environments, this is at least partly reality today. Many GUI programming tools let you construct at least the visual parts of an application by assembling components. The promised benefits of component-based development architectures include reusability (and therefore less repetitive work), reliability (if each part works separately, and they are assembled correctly, the whole assembly should work), and ease of understanding/maintenance (because parts can be understood separately). To be useful, a component architecture must include ways of: \begin{itemize} \item connecting components to form an application, \item packaging and distributing the components, and \item separating the work of an application into components. \end{itemize} Let's look at how PEAK addresses these issues. \subsection{Composing vs. Connecting} Imagine a car. It's composed from a variety of parts: the wheels, engine, battery, frame, and so on. Some of these parts are also composed of parts: the engine has a block, cylinders, pistons, spark plugs, and so on. Each part in this ``component assembly" can be a part of only one larger part: its \strong{parent component}. The hubcaps are part of the wheels, and so they can't also be part of the engine. (They wouldn't fit there in any case, but that's beside the point.) Consider that screws or bolts may be used in many parts of the car: each is part of only one other part of the car, although more than one of the same \emph{kind} of part may be used in other places. In the UML (Unified Modelling Language) and in PEAK, this kind of parent-child ``assembly" relationship is called \strong{composition}: a component is being ``composed" by assembling other components. But in the UML and in real life, this isn't the only way of building things with components. It would be very inefficient if every light and accessory in your car had to have its own, independent electrical system. Ways of \emph{sharing} components are needed. In the car, wires, pipes, hoses, and shafts serve to \emph{connect} the services provided by shared components to the places where they are needed. Note that such connections may be between components at any level: wires carry electricity to every electrical part, no matter how big or small. In some cases, wires go to a major subsystem, which then has internal wires to carry electricity inward to its parts, or to carry signals between its parts. In the UML, these kind of ``shared" or ``peer-to-peer" connections are called \strong{associations}. \subsubsection{Implementing Components in Python and PEAK} In the Python language, components are Python objects, and composition and association relationships are represented using objects' attributes. Using the \module{peak.binding} package, you'll create \strong{attribute bindings} that define what sub-objects will be created (via composition) or external objects will be referenced (via association) by each attribute of a component. Of course, there are some important differences between software and the real world. In the real world, we have to actually build every part of the car ``ahead of time", and we must have one screw for every place a screw is needed. In software, classes let us define the concept of a ``screw" once and then use it as many times as we want, anywhere that we want. Also, with PEAK, bindings are ``lazy". What this means is that we can define an ``engine" class whose parts aren't actually created until they're needed. We just list the parts that are needed and what attributes they'll be bound to, and when the attribute is used, the part is automatically created or connected, according to our definition. Since each part ``magically" appears the first time we want to use it, it's as though it was always there. It's as if your car was an empty shell until you opened the door or looked in the window, at which point all the contents magically appeared. And then when you got into the car, the radio was just an empty shell until you tried to turn it on, at which point all of its internal components sprang into being and wired themselves together. This ``lazy" construction technique can speed startup times for applications which are built from large numbers of components, by not creating all the objects right away, and by never creating objects that don't get used during that application run. \subsubsection{Component Interfaces} You can't just hook wires between random parts of your car and expect good results. In the same way, software components can only be ``wired" together if they have compatible interfaces. A software component that expects to send data to a ``file" component must be connected to a component that provides the same services a file would provide, even if the component is not actually a ``real" disk file. A specific set of services that a component provides is called an \strong{interface}. Interfaces can denote a component's requirements, as well as the guarantees that it provides when those requirements are met. In PEAK, interfaces are defined and declared using the \module{zope.interface} package (bundled with PEAK for your convenience). This means that components you create with PEAK's component architecture should also work in Zope X3's component architecture. (Which is important if you plan to build Zope X3-based applications and web services with PEAK.) Interfaces in PEAK are used primarily as documentation and as a way of finding compatible components and services. When used with the Zope X3 component architecture, interfaces can also be used to register adapters (which convert a component from one interface to another), declare web views of application components, and even define security restrictions based on interfaces. \vfill \begin{seealso}\begin{itemize} \item \citetitle{A Quick Introduction to Python Interfaces} at \url{http://www.zope.org/Wikis/Interfaces/InterfaceUserDocumentation}. \item And, if you're interested in developing Zope X3 applications and want to learn more about what you can do with interfaces in the XZope 3 component architecture, see \citetitle{Programming with the Zope 3 Component Architecture} at \url{http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/Zope3PythonProgrammerTutorialChapter1/ }. \end{itemize}\end{seealso} \vfill \subsection{Applications = Components + Bindings} For now, we're going to skip over the issue of packaging and distributing components. Since they're implemented as Python objects, we can use virtually any of the standard techniques for packaging and distributing Python code, such as the \module{distutils} package, or perhaps more elaborate systems such as Gordon MacMillan's cross-platform \citetitle{Installer} package. So let's move on to the third major aspect of a component architecture: separating the work of an application or system into components. \subsubsection{Why compose and connect?} Is it realistic to expect to be able to define an application entirely in terms of components? And why would you want to do it in the first place? Can't we just write an application the ``old-fashioned way"? That is, import the exact components we want, and use them wherever and whenever we want, instead of creating bindings to link them to a master ``application" component? Well, you could, but one of PEAK's goals is to improve reusability. Consider this: all cars have engines, but different models of car have different goals or requirements for their engines. If we are creating a ``Car" application, wouldn't it be nice if we could switch out the ``engine" component when we get a new project, without having to maintain multiple versions of the code? Perhaps for this project we need the ``car" to be compact, or perhaps we need a bigger engine for a station wagon this time. How can we achieve such reusability? It actually requires only a simple coding convention: never write code in a function or method that directly references another class. Instead, define \emph{all} collaborations with other classes by way of instance attributes. This means that collaborating component classes can be easily substituted in a derived class, substituting a new ``engine" class, for example. While you can apply this technique of ``hiding collaborators" in any object-oriented language, PEAK takes the approach to a new level. Because PEAK attribute bindings can be used to programmatically define connections in context, components can actually seek out their collaborators dynamically at runtime, via configuration files or other sources. This can be as simple and ubiquitous as looking up what database to connect to, or as complex as specifying strategy components to select algorithms that are optimal for a specific deployment environment. We're back to the ``ilities" again: reusability, composability, extensibility, and flexibility, in this case. (Maybe portability, too.) We even get a bit of understandability and maintainability: when we isolate collaborations in attribute bindings, it becomes a lot easier to implement the \citetitle{Law of Demeter} and write ``adaptive programs". \vfill \begin{seealso} \url{http://www.ccs.neu.edu/home/lieber/LoD.html} has lots of links about the \citetitle{Law of Demeter}, and you can also see \url{http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/object-formulation.html } for its ``object-oriented" version, if you'd like to know more about this software quality technique. PEAK takes this ``Law" very seriously, insisting that code which references even a collaborator class must do so via an instance attribute or other ``neighbor" as defined by the Law. You don't have to know or follow the \citetitle{Law of Demeter} to use PEAK. (Your programs just won't be as flexible.) But all of our example programs will obey the Law, so you'll have a chance to see how -- and how easy it is -- to follow it. \end{seealso} \vfill \subsubsection{Services, Elements, and Features} So what's an application made of? The PEAK approach describes application components in terms of their lifecycles and roles, as follows: \begin{description} \item[Services] \hfill \\ Similar in concept to ``singletons", Services are ``well-known" instance objects which exist for the lifetime of the application. For example, a database connection object in an application could be a service component, and so could a top-level window in a GUI application. J2EE ``session beans" and ``message-driven beans" are also good examples of service components. (Note: don't confuse this general concept of services with the Zope 3 concept of a ``Service"; the latter is an example of the former, but not necessarily the other way around.) \item[Elements] \hfill \\ Elements are typically ``problem-domain" objects or their proxies in the user interface. They are created and destroyed by other Elements or by the application's Services. Typical Elements might be ``business objects" such as customers and sales, but of course any object that is the actual subject of the application's purpose would be considered an Element. In a mail filtering program, for example, e-mail messages, mailboxes, and ``sender whitelist" objects would be considered Elements. \item[Features] \hfill \\ Features are ``solution-domain" objects used to compose Elements, and less often, to compose Services. Features are typically used to represent the properties, methods, associations, user interface views, database fields, and other ``features" of a problem-domain Element. Feature objects are often used as a class attribute in an Element's class, and shared between instances. PEAK makes extensive use of feature objects to implement labor-saving techniques such as generative programming. \end{description} This breakdown of application components is called the \strong{Service-Element-Feature (SEF) Pattern}. PEAK makes it easy to create components of each kind, but this pattern certainly isn't limited to PEAK. You'll find Services, Elements, and Features in almost any object-based application, regardless of language or platform. But, the pattern is often implemented in a rather haphazard fashion, and without the benefit of explicit ``wiring" between components. When you design an application using the SEF Pattern, your top-level application object is itself a Service. You construct that service from lower-level services, such as database connections, object managers, and maybe even a top-level window object for a GUI application. If your application is to be web-based, or you're constructing a middle-tier subsystem, perhaps it will be composed of web services or the equivalent of J2EE session beans. The top-level application object may provide various methods or ``value-added" services on top of its subcomponents' services, or it may just serve to start them up in an environment that defines their mutual collaborators. You may find later that what you thought was an ``application" component, is really just another service that you want to use as part of a larger application. Fortunately, it's easy to change a PEAK component's bindings and incorporate it into a larger system. Defining the Elements of your application design is also fairly straightforward. Elements are the subject of what your application \emph{does}. A business application might have Customer elements, a web server might handle Page elements, and a hard drive utility might manipulate Partition elements. Features, on the other hand, are usually provided by frameworks, and incorporated into your application's Elements to create a specific kind of application. For example, a GUI framework might provide visual features that allow mapping Element properties to input fields in a window. While PEAK does or will provide many Element and Feature base classes you can use to build your applications, these facilities are outside the scope of this tutorial, which focuses primarily on assembling an application's Service components. However, some of the techniques you'll learn here will be as applicable to Element and Feature objects as they are to Service components. So, let's get started on actually \emph{using} PEAK to build some components, shall we? \section{Specifying Attributes Using Bindings} \subsection{Binding Fundamentals} It's time to write some code! Our objective: create a ``car" class that keeps track of its passengers. \begin{verbatim% }>>> from peak.api import binding >>> class Car: passengers = binding.New(dict, name='passengers') >>> aCar=Car() >>> print aCar.passengers {} \end{verbatim} Let's go through this sample line by line. In the first line we import the \module{peak.binding} API. Then, we create a simple class, with one attribute, \member{passengers}. We define the attribute using the \function{binding.New} function, which creates an attribute binding from a type and an optional name. Instances of class \class{Car} will each get their own \member{passengers} attribute, which contains a new (hence the name, \function{binding.New}) dictionary. If you're new to Python, you might wonder why we don't place a dictionary directly in the class, like this: \begin{verbatim% }class Car: passengers = {} \end{verbatim} The problem is that attributes defined in a Python class body are shared, so every car will end up with the same passenger dictionary. Experienced Python programmers solve this problem by placing code in their \method{__init__} method to initialize the structure, like so: \begin{verbatim% }class Car: def __init__(self): self.passengers = {} \end{verbatim} This works alright for simple situations, but gets more complex when you use inheritance to create subclasses of \class{Car}. It becomes necessary to call the superclass \method{__init__} methods, and the order of initialization for different attributes can get tricky. If you develop in Java or C++ or some other language that has instance variable initializers, you'll be happy to know that PEAK lets you have them in Python too -- only better. In most static languages, variable initializers run at object creation time. So, either you create \emph{all} of an object's collaborators at creation time, or you write accessor functions to hide whether the fields or attributes are initialized. This can be quite tedious in complex programs. But PEAK's attribute bindings are \strong{lazy}. They do not compute their value until they are used. If we take a new instance of our \class{Car} class, and print its dictionary before and after referencing the \member{passengers} attribute: \begin{verbatim% }>>> anotherCar=Car() >>> print anotherCar.__dict__ {} >>> print anotherCar.passengers {} >>> print anotherCar.__dict__ {'passengers': {}} \end{verbatim} We find that the object doesn't really \emph{have} the attribute until we try to access it, but once we do access it, it springs into being as though it had always been there, and it acts like a normal attribute thereafter. If you're familiar with the Eiffel programming language, you'll notice that PEAK attribute bindings are quite similar to Eiffel's \strong{once functions}, except that they're for instances rather than for classes. A ``once function" is computed at most once, the first time its value is referenced. In PEAK, virtually all attribute bindings are based on \class{binding.Once}, a class that handles most of the mechanics needed to make these ``once attributes" work. \subsubsection{Deriving from \class{binding.Component}} As we've already seen, attribute bindings can be made to work with ``old-style" or ``classic" Python classes. There are some drawbacks to that, however. Most visibly, it's necessary to specify an attribute binding's name in its definition, as we saw in our example, i.e. \samp{passengers = binding.New(dict, 'passengers')}. However, if we derive our class from \class{binding.Component}, we no longer have to do this: \begin{verbatim% }>>> class Car(binding.Component): passengers = binding.New(dict) >>> aCar=Car() >>> print aCar.passengers {} \end{verbatim} Now, it's sufficient to use \samp{binding.New(dict)} to define the attribute. What would happen if we did this \emph{without} \class{binding.Component}? \begin{verbatim% }>>> class Car(object): # new-style class error messages are more helpful passengers = binding.New(dict) >>> aCar=Car() >>> print aCar.passengers Traceback (most recent call last): File "", line 1, in ? print aCar.passengers File "C:\cygwin\home\pje\PEAK\src/peak/binding/_once.pyx", line 119, in __get__ raise File "C:\cygwin\home\pje\PEAK\src/peak/binding/_once.pyx", line 104, in __get__ self.usageError() File "C:\cygwin\home\pje\PEAK\src\peak\binding\once.py", line 177, in usageError raise TypeError( TypeError: was used in a type which does not support active bindings, but a valid attribute name was not supplied \end{verbatim} Ouch! It doesn't work, because PEAK can't tell what name the attribute has without help from either you or the base class. (Actually, it's the metaclass, not the base class, but that's not important right now). There are some circumstances where PEAK will try to guess the attribute name for you, such as when you use a class or a function to define an attribute binding, but for the most part you must either have a base class (such as \class{binding.Component}) whose metaclass supports activating bindings, or else you must supply the attribute name yourself when defining the binding. So, if you plan to use attribute bindings in your program, it's probably best to subclass \class{binding.Component}; it'll save you a lot of typing! Most PEAK framework classes for ``service" components derive from \class{% binding.Component} alredy. \newpage \subsubsection{\class{binding.Once} - The Basis for all Bindings} All PEAK bindings are created using the class \class{binding.Once}, or a subclass thereof. It provides the basic machinery needed to lazily compute an attribute "on-the-fly". Here's a simple example of its use: \begin{verbatim% }class Car(binding.Component): def height(self,instDict,attrName): baseHeight = self.roof.top - self.chassis.bottom return self.wheels.radius + baseHeight height = binding.Once(height) \end{verbatim} In this example, we want to compute the car's height based on various other attributes, but we only want to compute it once, and save the value thereafter. To do this, we define a function that takes three arguments: the object, its instance dictionary, and the name of the attribute being computed. Most of the time, you'll only care about the first argument, which is the object for which the attribute is being computed. It's rare that you'll need the instance dictionary or the attribute name, but if you need them, they're there. Normally, you'll just return the value you want the attribute to end up with. %XXX add reasons why you might want to use them Note, by the way, that there's no need for this function passed to \class{binding.Once} to be a method, or for the parameters to have specific names. If we continued the class above as follows: \begin{verbatim% } verticalCenter = binding.Once(lambda s,d,a: s.height/2) \end{verbatim} This would be a perfectly valid way to express the idea that the car's vertical center is half of its height. It's also true that we could say: \begin{verbatim% } passengers = binding.Once(lambda s,d,a: {}) \end{verbatim} as another way of saying \samp{binding.New(dict)}. However, the \function{binding.New} function is more compact, and clearer as to intention. Of course, \function{binding.New} is actually implemented by creating a function and wrapping it in a \class{binding.Once} instance, in just the same way as we might do it ``by hand". By the way, although we've been only showing uses of \class{binding.Once} with one argument (the function to be called), \class{binding.Once} does actually take other arguments, such as a default attribute name, a ``provides" specification (more on this later) and a docstring. Check out the PEAK API Reference or the source code for more details. \subsubsection{Re-binding, Pre-binding, Un-binding, and Persistence} We've mentioned over and over that attribute bindings are computed only once, but that's not precisely true. It's actually possible for them to be computed zero times, or many times, if we set or delete the attribute the binding defines. You may have wondered, ``how does a binding know whether it's been computed or not?" It knows because there is an entry in the object's dictionary for that attribute name. (Notice, by the way, that this means objects without dictionaries can't get much use out of bindings.) But what if there's something already in the dictionary? Or what if you remove the value from the dictionary? Well, it's pretty much as you'd expect. If you set a value for an attribute, then the binding will not compute a value. If you delete the attribute, and try to access it, the binding will recompute the value. This behavior can actually be quite useful in the context of transactions: many PEAK transactional components delete certain bindings at the conclusion of a transaction, allowing them to be recomputed in the next transaction. PEAK also makes use of the ability to override a binding by manually setting a value for an attribute. For example, most PEAK component classes' \method{__init__} methods accept keyword arguments which can override attributes which would otherwise be determined by bindings. This is especially useful in conjunction with the \class{binding.requireBinding} class, which simply raises an error when you try to access the attribute. It's a handy way of specifying that a component must have the attribute, and that a subclass or instance must supply the value. By the way, it's important to note that bindings do \emph{not} participate in persistence, as they directly alter the associated object's dictionary, bypassing the normal ``set attribute" machinery. You should carefully consider the use of attribute bindings in persistent objects, as to how they will interact with your persistence machinery (e.g. whether they should be saved or not) and whether you will want to code them in such a way as to consider the object ``changed" when an attribute is computed. \subsection{Creating Attribute Bindings} The \module{peak.binding} package offers many kinds of attribute bindings for constructing your components. In this section, we'll look at the conventions for how these bindings are created, and at the details of several of the basic binding types. \subsubsection{API Conventions} There are four standard parameters that almost all attribute binding constructors accept. They always use the same parameter names, so you can supply them as keyword arguments. \begin{description} \item[\var{name}] \hfill \\ The \var{name} parameter specifies the attribute name that the binding will have. As mentioned previously, this is only needed when the binding is being used in a class that doesn't support active descriptors. If you're using a class that inherits from \class{binding.Component}, you don't need to supply this parameter. \item[\var{provides}] \hfill \\ The \var{provides} parameter is a (possibly nested) tuple of \strong{configuration keys}, which are either interfaces or \class{PropertyName} objects. This is used for integration with the configuration system, so we'll explore it in more detail later on. For now, you can just ignore it. \item[\var{doc}] \hfill \\ The \var{doc} parameter is an optional docstring which will be used for the attribute. This is useful for documenting your class so that tools like \citetitle{pydoc} and the Python \function{help} function will display the docstring for the attribute as part of the class' documentation. \item[\var{activateUponAssembly}] \hfill \\ \var{activateUponAssembly} is a flag that indicates whether the attribute should be computed when the object's \method{uponAssembly} method is called. We haven't covered ``assembly events" yet, so don't worry about this one for now. \end{description} \subsubsection{Basic Binding Classes/Functions} The following functions and classes can be used as-is to create attribute bindings, or you can subclass the classes to create custom binding types of your own: \begin{funcdesc}{Once}{func, name=None, provides=None, doc=None, activateUponAssembly=False} The most basic of all binding types, the \class{binding.Once} class requires only a callable object such as a function or lambda. If you don't supply a \var{name}, the \samp{__name__} attribute of the \var{func} parameter is used, if available. Similarly, if you don't supply a \var{doc}, the \samp{__doc__} attribute of the \var{func} parameter is used, if available. \end{funcdesc} \begin{funcdesc}{New}{obtype, bindToOwner=None, name=None, provides=None, doc=None, activateUponAssembly=False} As we've already seen, the \function{binding.New} function just needs a class or type object as its \var{obtype} parameter, and it creates a new instance of that type. The optional \var{bindToOwner} flag, if specified, tells \function{binding.New} whether it should pass the owning object and attribute name into the type's constructor. If you don't specify a value for this parameter, the \function{binding.New} function will ``guess" by checking whether the constructor supports the \class{binding.IComponentFactory} interface. Ordinarily, you can ignore this parameter, and the ``right thing" will happen. \function{binding.New} will also accept a string for its \var{obtype} parameter, in which case it will interpret the string as an \strong{import specification}, using the \function{peak.util.imports.importString} function to load it. We'll talk more about import specifications in the chapter on the \module{peak.config} package. \end{funcdesc} \begin{funcdesc}{Copy}{obj, name=None, provides=None, doc=None, activateUponAssembly=False} The \function{binding.Copy} function does just what it says. When accessed, it will create a copy of its \var{obj} parameter, using the \function{copy} function from the Python standard library's \module{copy} module. \end{funcdesc} \begin{funcdesc}{bindToSelf}{name=None, provides=None, doc=None} This one is pretty self-explanatory, no pun intended. This class supplies the owning object itself as an instance attribute. What good is that? Well, it's handy for objects that provide default support for various interfaces in the absence of an object to delegate the implementation to. The object can refer to \samp{self.delegateForInterfaceX.someMethod()}, and have the \samp{delegateForInterfaceX} attribute be a \class{binding.bindToSelf} instance by default. \end{funcdesc} \begin{funcdesc}{requireBinding}{description="", name=None, provides=None, doc=None} The \function{binding.requireBinding} class is the odd one out in this group. It doesn't compute a value at all! Instead, it raises an error when the attribute is accessed. This is so that you can easily define an attribute that you expect a subclass or instance to provide, and thus get a clearer error message if the expected attribute is never defined. \end{funcdesc} \newpage \section{Composing Hierarchies with Bindable Components} So far, we've only looked at binding various kinds of ``helper" attributes into components, but not assembling components themselves into larger components or applications. One issue that arises quite a bit in the assembly of components is the notion of \strong{context}. A component often needs to know ``where" it is located, in the sense of its placement in a larger component. While components will typically have many connections to other components, the connection between a component and its container or \strong{parent component} is particularly important. Let's look at an example: \begin{verbatim% }>>> class Wheel(binding.Component): def spin(self): print "I'm moving at %d mph" % self.getParentComponent().speed >>> class Car(binding.Component): wheel = binding.New(Wheel) speed = 50 >>> c = Car() >>> c.wheel.spin() I'm moving at 50 mph \end{verbatim} The \class{binding.Component} class defines two methods for dealing with parent components: \function{getParentComponent} and \function{setParentComponent}. \function{setParentComponent} is automatically called for you when you create an instance via \function{binding.New}, which is why our \class{Wheel} instance above was able to access its parent component with \function{% getParentComponent}. Let's look at a slightly different version of that example: \begin{verbatim% }>>> class Wheel(binding.Component): def spin(self): print "I'm moving at %d mph" % self.speed speed = binding.bindTo('../speed') >>> class Car(binding.Component): wheel = binding.New(Wheel) speed = 50 >>> c = Car() >>> c.wheel.spin() I'm moving at 50 mph \end{verbatim} By now, perhaps the wheels in your brain will be spinning as well, thinking about the possibilities here. \newpage \subsection{Inspecting Component Hierarchies} The \module{peak.binding} package supplies several useful functions for examining relationships between components. Let's run through a few examples, continuing the previous example above: \begin{verbatim% }>>> print c <__main__.Car object at 0x00F7BCB0> >>> print binding.getParentComponent(c.wheel) <__main__.Car object at 0x00F7BCB0> >>> class Transport(Car): cargo = binding.New(Car) >>> t=Transport() >>> print t <__main__.Transport object at 0x00FA1670> >>> print binding.getRootComponent(t.cargo.wheel) <__main__.Transport object at 0x00FA1670> >>> print binding.getComponentName(t.cargo.wheel) wheel >>> print binding.getComponentPath(t.cargo.wheel) /cargo/wheel >>> print binding.getComponentPath(t.wheel) /wheel >>> print t.cargo <__main__.Car object at 0x00FABB70> >>> print binding.getParentComponent(t.cargo.wheel) <__main__.Car object at 0x00FABB70> >>> binding.lookupComponent('/cargo/wheel',t) <__main__.Wheel object at 0x00FAB900> \end{verbatim} As you can see, \function{binding.getParentComponent}, \function{binding.% getRootComponent}, \function{binding.lookupComponent}, \function{binding.% getComponentName}, and \function{binding.getComponentPath} do pretty much as you would expect from their names. (One thing we didn't show, however, was that \function{binding.getComponentPath} doesn't actually return a string, but a \class{binding.ComponentName} instance that just looks like a string when printed. More about this later.) \subsubsection{How Hierarchies Are Assembled} Perhaps you've been wondering how the objects know what objects are their parents. In the process of answering that question, we'll pass through lots of interesting or important points along the way. The short answer to how an object knows what its parent is, is that you tell it. The constructor for \class{binding.Component} takes as its very first argument, the object which should be its parent. In our examples above, however, we never passed a parent into a constructor. We created the \class{Car} instance and \class{Transport} instance without supplying a parent component. So those instances were created without a parent, which is why when we inspect them, they show up as parentless or \strong{root components}. In PEAK, a root component is any object without a parent. Only objects whose classes provide a \function{getParentComponent} method can have parents, and even then they are only considered to have a parent if that method returns something other than \samp{None}. Classes without such a method, such as Python built-in types, are almost always root components. For example: \begin{verbatim% }>>> print binding.getParentComponent(123456) None >>> print binding.getRootComponent([1,2,3]) [1, 2, 3] >>> print binding.getComponentPath("a string") / >>> print binding.lookupComponent("upper", "another string") \end{verbatim} As you can see, the inspection functions provided by \module{peak.binding} will work with just about any kind of object, and will provide results consistent with the interpretation that objects without a \function{% getParentComponent} method are root components. Notice also that an object doesn't have to be based on \class{binding.Component} to work in a component hierarchy; all it needs is a \function{% getParentComponent} method defined in its class. For example: \begin{verbatim% }>>> class myGUIControl: def getParentComponent(self): return self.parentWindow >>> aControl = myGUIControl() >>> aControl.parentWindow = "just a demo" >>> print binding.getParentComponent(aControl) just a demo \end{verbatim} This, by the way, is one of the reasons why it's better to use \module{% peak.binding} functions to inspect components instead of calling their \function{getParentComponent} or other methods directly. \function{binding.% getParentComponent} has code to handle the case where an object has no \function{getParentComponent} method. Similarly, other inspection functions gracefully handle the absence of appropriate support by the object: \begin{verbatim% }>>> print binding.getComponentName(aControl) None >>> print binding.getComponentPath(aControl) /* \end{verbatim} Notice that since we didn't provide any special support in our example GUI control class for component names, the \module{peak.binding} system considers it not to have a name. And unknown names show up as \samp{'*'} in component path segments. % XXX module hierarchy lookups Of course, if we wanted to support our hypothetical GUI controls having component names, we would need only to add a \function{getComponentName} method to its class. But how do we know what methods to add, and what values they should accept or return? The \module{peak.binding} framework defines an \strong{interface}, \class{binding.IBindingNode}, that defines what methods the binding framework calls on objects that it expects to be nodes in a component tree. The \class{binding.IBindingNode} interface looks basically like this: \begin{verbatim% }class IBindingNode(config.IConfigSource): """Minimum requirements to join a component hierarchy""" def getParentComponent(): """Return the parent component of this object, or 'None'""" def getComponentName(): """Return this component's name relative to its parent, or 'None'""" def notifyUponAssembly(child): """Call 'child.uponAssembly()' when component knows its root""" \end{verbatim} By convention, interface names in Python are usually begun with a captial ``I", to help distinguish them from regular classes. Also by convention, methods are described from the \emph{caller's} perspective, so \samp{self} arguments are not included in method definitions. So, the \class{binding.IBindingNode} interface tells us that to implement the Binding Node interface, we need a \function{getParentComponent} method and a \function{getComponentName} method, neither of which takes any parameters, and whose return values are as documented. This interface also inherits from \class{config.IConfigSource}, which defines some additional methods that a binding component should implement. We'll look at those in the coming chapter on the configuration system. Notice that this does \emph{not} mean a component has to inherit from \class{% IConfigSource}! It simply means that a class which promises to implement the \class{binding.IBindingNode} interface is also promising to implement the \class{config.IConfigSource} interface as well. Did our example \class{myGUIControl} class promise to implement \class{% binding.IBindingNode}? No. It doesn't have an \samp{__implements__} attribute or inherit one, so it's not promising to implement the full \class{IBindingNode} interface. This is acceptable because \module{peak.binding} verifies the presence of needed methods automatically, and it isn't required that a component implement all of the \class{IBindingNode} methods. Many other interfaces however, \emph{must} be explicitly promised by a class in order for the functionality to work. The \class{binding.IComponentFactory} interface is a good example of this. \class{IComponentFactory} is the interface which defines how component constructors work - at least if they're to be supported by \module{% peak.binding}! You may recall that we said earlier that component constructors accept their parent component as the first argument. But we didn't say what other arguments they took, or how it was that many objects in our examples wound up with parents even though we never supplied any arguments to their constructors. Well, we're about to see how that works. When a \function{binding.New} binding is activated, it checks to see if its \var{obtype} parameter implements \class{IComponentFactory}. If so, it knows that the constructor accepts the appropriate parameters, and supplies them when constructing the new instance. If the \var{obtype} parameter doesn't implement \class{IComponentFactory}, it's simply called without any parameters. (If you should need to, you can always override this behavior of \function{binding.New} using the \var{bindToOwner} flag.) Let's take a look at the \class{binding.IComponentFactory} interface in more detail. \begin{verbatim% }class IComponentFactory(Interface): """Class interface for creating bindable components""" def __call__(parentComponent=None, componentName=None, **attrVals): """Create a new component The default constructor signature of a binding component is to receive an optional parent to be bound to, an optional name relative to the parent, and keyword arguments which will be placed in the new object's dictionary, to override the specified bindings.""" \end{verbatim} Notice that this interface describes a \function{__call__} method. This doesn't mean that you'll need a \function{__call__} method on your object instances or in your class. It simply means that an object that implements the interface should be callable. Because \class{IComponentFactory} is an interface for functions or classes, the \function{__call__} method simply documents what behavior the function or class constructor should have. XXX show how to implement in a class, __init__, __class_implements__, etc. XXX IComponent interface; setParentComponent \subsubsection{Names and Paths} XXX lookupComponent \subsection{Hierarchy-Building Tools} XXX Component, bindToParent, ... \section{Connecting Components by Name or Interface} XXX bindSequence, bindTo, bindToProperty, bindToUtilities, Constant, Acquire, ComponentName, ... XXX Stuff that needs to go to config chapter: iterParents, findUtility, findUtilities