[Checkins] SVN: zope2docs/branches/baijum-reorganize/ - Moved sources to zdgbook directory

Baiju M baiju.m.mail at gmail.com
Sat Oct 10 02:04:17 EDT 2009


Log message for revision 104984:
  - Moved sources to zdgbook directory
  - Removed buildout and Sphinx conf
  

Changed:
  U   zope2docs/branches/baijum-reorganize/index.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/Acquisition.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/AppendixA.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/ComponentsAndInterfaces.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/Credits.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/GettingStarted.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.stx
  A   zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.txt
  A   zope2docs/branches/baijum-reorganize/zdgbook/Introduction.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/Makefile
  A   zope2docs/branches/baijum-reorganize/zdgbook/ObjectPublishing.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/Outline.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/Products.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/Security.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/TestingAndDebugging.rst
  A   zope2docs/branches/baijum-reorganize/zdgbook/ZODBPersistentComponents.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/bootstrap.py
  D   zope2docs/branches/baijum-reorganize/zdgbook/build/
  D   zope2docs/branches/baijum-reorganize/zdgbook/buildout.cfg
  A   zope2docs/branches/baijum-reorganize/zdgbook/index.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/Acquisition.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/AppendixA.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/ComponentsAndInterfaces.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/Credits.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/GettingStarted.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/Introduction.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/ObjectPublishing.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/Outline.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/Products.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/Security.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/TestingAndDebugging.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/ZODBPersistentComponents.rst
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/conf.py
  D   zope2docs/branches/baijum-reorganize/zdgbook/source/index.rst

-=-
Modified: zope2docs/branches/baijum-reorganize/index.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/index.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/index.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -6,7 +6,7 @@
    :maxdepth: 1
 
    zope2book/index
-   zdgbook/source/index
+   zdgbook/index
 
 Release information
 ===================

Copied: zope2docs/branches/baijum-reorganize/zdgbook/Acquisition.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/Acquisition.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/Acquisition.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/Acquisition.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,457 @@
+###########
+Acquisition
+###########
+
+Acquisition is a mechanism that allows objects to obtain attributes
+from their environment.  It is similar to inheritance, except that,
+rather than searching an inheritance hierarchy to obtain attributes,
+a containment hierarchy is traversed.
+
+
+Introductory Example
+====================
+
+Zope implements acquisition with "Extension Class" mix-in classes. To
+use acquisition your classes must inherit from an acquisition base
+class. For example::
+
+  import ExtensionClass, Acquisition
+
+  class C(ExtensionClass.Base):
+    color = 'red'
+
+  class A(Acquisition.Implicit):
+
+    def report(self):
+      print self.color
+
+  a = A()
+  c = C()
+  c.a = A()
+
+  c.a.report() # prints 'red'
+
+  d = C()
+  d.color = 'green'
+  d.a = a
+
+  d.a.report() # prints 'green'
+
+  a.report() # raises an attribute error
+
+The class 'A' inherits acquisition behavior from
+'Acquisition.Implicit'.  The object, 'a', "has" the color of objects
+'c' and 'd' when it is accessed through them, but it has no color by
+itself.  The object 'a' obtains attributes from its environment,
+where its environment is defined by the access path used to reach
+'a'.
+
+Acquisition Wrappers
+====================
+
+When an object that supports acquisition is accessed through an
+extension class instance, a special object, called an acquisition
+wrapper, is returned.  In the example above, the expression 'c.a'
+returns an acquisition wrapper that contains references to both 'c'
+and 'a'.  It is this wrapper that performs attribute lookup in 'c'
+when an attribute cannot be found in 'a'.
+
+Acquisition wrappers provide access to the wrapped objects through
+the attributes 'aq_parent', 'aq_self', 'aq_base'.  In the example
+above, the expressions::
+
+  'c.a.aq_parent is c'
+
+and::
+
+  'c.a.aq_self is a'
+
+
+both evaluate to true, but the expression::
+
+  'c.a is a'
+
+evaluates to false, because the expression 'c.a' evaluates to an
+acquisition wrapper around 'c' and 'a', not 'a' itself.
+
+The attribute 'aq_base' is similar to 'aq_self'.  Wrappers may be
+nested and 'aq_self' may be a wrapped object.  The 'aq_base'
+attribute is the underlying object with all wrappers removed.
+
+You can manually wrap an instance of an object that inherits from an
+acquisition base class by using its '__of__' method. For example::
+
+  class A(Acquisition.Implicit):
+      pass
+
+  a = A()
+  a.color = 'red'
+  b = A()
+  a.b = b
+
+  print b.__of__(a).color # prints red
+
+
+The expression 'b.__of__(a)' wraps 'b' in an acquisition wrapper
+explicitly, and returns the acquisition wrapper.  The 'color'
+attrribute of 'a' is found via acquisition when this expression is
+executed.
+
+
+Explicit and Implicit Acquisition
+=================================
+
+Two styles of acquisition are supported: implicit and explicit
+acquisition.
+
+Implicit acquisition
+--------------------
+
+Implicit acquisition is so named because it searches for
+attributes from the environment automatically whenever an
+attribute cannot be obtained directly from an object or through
+inheritance.
+
+An attribute can be implicitly acquired if its name does not
+begin with an underscore.
+
+To support implicit acquisition, your class should inherit from
+the mix-in class 'Acquisition.Implicit'.
+
+Explicit Acquisition
+--------------------
+
+When explicit acquisition is used, attributes are not automatically
+obtained from the environment.  Instead, the method 'aq_acquire' must
+be used. For example::
+
+  print c.a.aq_acquire('color')
+
+To support explicit acquisition, your class should inherit from the
+mix-in class 'Acquisition.Explicit'.
+
+Controlling Acquisition
+=======================
+
+A class (or instance) can provide attribute by attribute control over
+acquisition.  Your should subclass from 'Acquisition.Explicit', and
+set all attributes that should be acquired to the special value
+'Acquisition.Acquired'.  Setting an attribute to this value also
+allows inherited attributes to be overridden with acquired ones.  For
+example::
+
+  class C(Acquisition.Explicit):
+     id=1
+     secret=2
+     color=Acquisition.Acquired
+     __roles__=Acquisition.Acquired
+
+The *only* attributes that are automatically acquired from containing
+objects are 'color', and '__roles__'.  Note that the '__roles__'
+attribute is acquired even though its name begins with an underscore.
+In fact, the special 'Acquisition.Acquired' value can be used in
+'Acquisition.Implicit' objects to implicitly acquire selected objects
+that smell like private objects.
+
+Sometimes, you want to dynamically make an implicitly acquiring
+object acquire explicitly. You can do this by getting the object's
+'aq_explicit' attribute. This attribute provides the object with an
+explicit wrapper that places the original implicit wrapper.
+
+Filtered Acquisition
+====================
+
+The acquisition method, 'aq_acquire', accepts two optional
+arguments. The first of the additional arguments is a "filtering"
+function that is used when considering whether to acquire an object.
+The second of the additional arguments is an object that is passed as
+extra data when calling the filtering function and which defaults to
+'None'.  The filter function is called with five arguments:
+
+- The object that the 'aq_acquire' method was called on,
+
+- The object where an object was found,
+
+- The name of the object, as passed to 'aq_acquire',
+
+- The object found, and
+
+- The extra data passed to 'aq_acquire'.
+
+If the filter returns a true object that the object found is
+returned, otherwise, the acquisition search continues.
+
+For example, in::
+
+  from Acquisition import Explicit
+
+  class HandyForTesting:
+      def __init__(self, name):
+          self.name = name
+      def __str__(self):
+          return "%s(%s)" % (self.name, self.__class__.__name__)
+      __repr__ = __str__
+
+  class E(Explicit, HandyForTesting): pass
+
+  class Nice(HandyForTesting):
+      isNice = 1
+      def __str__(self):
+          return HandyForTesting.__str__(self) + ' and I am nice!'
+      __repr__ = __str__
+
+  a = E('a')
+  a.b = E('b')
+  a.b.c = E('c')
+  a.p = Nice('spam')
+  a.b.p = E('p')
+
+  def find_nice(self, ancestor, name, object, extra):
+      return hasattr(object,'isNice') and object.isNice
+
+  print a.b.c.aq_acquire('p', find_nice)
+
+The filtered acquisition in the last line skips over the first
+attribute it finds with the name 'p', because the attribute doesn't
+satisfy the condition given in the filter. The output of the last
+line is::
+
+  spam(Nice) and I am nice!
+
+Filtered acquisition is rarely used in Zope.
+
+Acquiring from Context
+======================
+
+Normally acquisition allows objects to acquire data from their
+containers. However an object can acquire from objects that aren't
+its containers.
+
+Most of the example's we've seen so far show establishing of an
+acquisition *context* using 'getattr' symanitics. For example, 'a.b'
+is a reference to 'b' in the context of 'a'.
+
+
+You can also manuallyset acquisition context using the '__of__'
+method.  For example::
+
+  from Acquisition import Implicit
+  class C(Implicit): pass
+  a = C()
+  b = C()
+  a.color = "red"
+  print b.__of__(a).color # prints red
+
+In this case, 'a' does not contain 'b', but it is put in 'b''s
+context using the '__of__' method.
+
+Here's another subtler example that shows how you can construct an
+acquisition context that includes non-container objects::
+
+  from Acquisition import Implicit
+
+  class C(Implicit):
+      def __init__(self, name):
+          self.name = name
+
+  a = C("a")
+  a.b = C("b")
+  a.b.color = "red"
+  a.x = C("x")
+
+  print a.b.x.color # prints red
+
+Even though 'b' does not contain 'x', 'x' can acquire the 'color'
+attribute from 'b'. This works because in this case, 'x' is accessed
+in the context of 'b' even though it is not contained by 'b'.
+
+Here acquisition context is defined by the objects used to access
+another object.
+
+Containment Before Context
+==========================
+
+If in the example above suppose both 'a' and 'b' have an 'color'
+attribute::
+
+  a = C("a")
+  a.color = "green"
+  a.b = C("b")
+  a.b.color = "red"
+  a.x = C("x")
+
+  print a.b.x.color # prints green
+
+
+Why does 'a.b.x.color' acquire 'color' from 'a' and not from 'b'?
+The answer is that an object acquires from its containers before
+non-containers in its context.
+
+To see why consider this example in terms of expressions using the
+'__of__' method::
+
+   a.x -> x.__of__(a)
+
+   a.b -> b.__of__(a)
+
+   a.b.x -> x.__of__(a).__of__(b.__of__(a))
+
+Keep in mind that attribute lookup in a wrapper is done by trying to
+look up the attribute in the wrapped object first and then in the
+parent object.  So in the expressions above proceeds from left to
+right.
+
+
+The upshot of these rules is that attributes are looked up by
+containment before context.
+
+This rule holds true also for more complex examples. For example,
+'a.b.c.d.e.f.g.attribute' would search for 'attribute' in 'g' and all
+its containers first. (Containers are searched in order from the
+innermost parent to the outermost container.) If the attribute is not
+found in g or any of its containers, then the search moves to 'f' and
+all its containers, and so on.
+
+Additional Attributes and Methods
+=================================
+
+You can use the special method 'aq_inner' to access an object wrapped
+only by containment. So in the example above::
+
+  a.b.x.aq_inner
+
+is equivalent to::
+
+  a.x
+
+You can find out the acquisition context of an object using the
+'aq_chain' method like so::
+
+  a.b.x.aq_chain # returns [x, b, a]
+
+You can find out if an object is in the acquisition context of
+another object using the 'aq_inContextOf' method. For example::
+
+  a.b.x.aq_inContextOf(a.b) # returns 1
+
+
+You can also pass an additional argument to 'aq_inContextOf' to
+indicate whether to only check containment rather than the full
+acquisition context. For example::
+
+  a.b.x.aq_inContextOf(a.b, 1) # returns 0
+
+Note: as of this writing the 'aq_inContextOf' examples don't
+work. According to Jim, this is because 'aq_inContextOf' works by
+comparing object pointer addresses, which (because they are actually
+different wrapper objects) doesn't give you the expected results. He
+acknowledges that this behavior is controversial, and says that there
+is a collector entry to change it so that you would get the answer
+you expect in the above. (We just need to get to it).
+
+
+Acquisition Module Functions
+----------------------------
+
+In addition to using acquisition attributes and methods directly on
+objects you can use similar functions defined in the 'Acquisition'
+module. These functions have the advantage that you don't need to
+check to make sure that the object has the method or attribute before
+calling it.
+
+'aq_acquire(object, name [, filter, extra, explicit, default, containment])' -- Acquires an object with the given name.
+
+This function can be used to explictly acquire when using explicit
+acquisition and to acquire names that wouldn't normally be acquired.
+
+The function accepts a number of optional arguments:
+
+- 'filter' -- A callable filter object that is used to decide if an
+  object should be acquired.
+
+  The filter is called with five arguments:
+
+  - The object that the aq_acquire method was called on,
+
+  - The object where an object was found,
+
+  - The name of the object, as passed to aq_acquire,
+
+  - The object found, and
+
+  - The extra argument passed to aq_acquire.
+
+  If the filter returns a true object that the object found is
+  returned, otherwise, the acquisition search continues.
+
+- 'extra' -- extra data to be passed as the last argument to the
+  filter.
+
+- 'explicit' -- A flag (boolean value) indicating whether explicit
+  acquisition should be used. The default value is true.  If the flag
+  is true, then acquisition will proceed regardless of whether
+  wrappers encountered in the search of the acquisition hierarchy are
+  explicit or implicit wrappers. If the flag is false, then parents
+  of explicit wrappers are not searched.
+
+  This argument is useful if you want to apply a filter without
+  overriding explicit wrappers.
+
+- 'default' -- A default value to return if no value can be acquired.
+
+- 'containment' -- A flag indicating whether the search should be
+  limited to the containment hierarchy.
+
+In addition, arguments can be provided as keywords.
+
+- 'aq_base(object)' -- Return the object with all wrapping removed.
+
+- 'aq_chain(object [, containment])' -- Return a list containing the
+  object and it's acquisition parents. The optional argument,
+  'containment', controls whether the containment or access hierarchy
+  is used.
+
+- 'aq_get(object, name [, default, containment])' -- Acquire an
+  attribute, name. A default value can be provided, as can a flag
+  that limits search to the containment hierarchy.
+
+- 'aq_inner(object)' -- Return the object with all but the innermost
+  layer of wrapping removed.
+
+- 'aq_parent(object)' -- Return the acquisition parent of the object
+  or 'None' if the object is unwrapped.
+
+- 'aq_self(object)' -- Return the object with one layer of wrapping
+  removed, unless the object is unwrapped, in which case the object
+  is returned.
+
+In most cases it is more convenient to use these module functions
+instead of the acquisition attributes and methods directly.
+
+Acquisition and Methods
+=======================
+
+Python methods of objects that support acquisition can use acquired
+attributes.  When a Python method is called on an object that is
+wrapped by an acquisition wrapper, the wrapper is passed to the
+method as the first argument.  This rule also applies to user-defined
+method types and to C methods defined in pure mix-in classes.
+
+Unfortunately, C methods defined in extension base classes that
+define their own data structures, cannot use aquired attributes at
+this time.  This is because wrapper objects do not conform to the
+data structures expected by these methods. In practice, you will
+seldom find this a problem.
+
+Conclusion
+==========
+
+Acquisition provides a powerful way to dynamically share information
+between objects. Zope using acquisition for a number of its key
+features including security, object publishing, and DTML variable
+lookup. Acquisition also provides an elegant solution to the problem
+of circular references for many classes of problems. While
+acquisition is powerful, you should take care when using acquisition
+in your applications. The details can get complex, especially with
+the differences between acquiring from context and acquiring from
+containment.

Copied: zope2docs/branches/baijum-reorganize/zdgbook/AppendixA.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/AppendixA.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/AppendixA.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/AppendixA.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,123 @@
+#################################
+Appendix A: Zope Core Permissions
+#################################
+
+This is a list of standard permissions included with Zope.  It is a
+good idea to use these permissions when applicable with your Zope
+products, rather than creating new ones.  A list of built-in Zope
+permissions are available in Zope source code:
+``src/AccessControl/Permissions.py``.
+
+Core Permissions
+================
+
+- Access contents information -- get "directory listing" info
+
+- Add Accelerated HTTP Cache Managers -- add HTTP Cache Manager objects
+
+- Add Database Methods -- add ZSQL Method objects
+
+- Add Documents, Images, and Files -- add DTML Method/Document objects,
+  Image objects, and File objects
+
+- Add External Methods  -- add External Method objects
+
+- Add Folders -- add Folder objects
+
+- Add MailHost objects  -- add MailHost objects
+
+- Add Python Scripts  -- Add Python Script objects
+
+- Add RAM Cache Managers  -- Add RAM Cache manager objects
+
+- Add Site Roots -- add Site Root objects
+
+- Add User Folders  -- add User Folder objects
+
+- Add Versions  -- add Version objects
+
+- Add Virtual Host Monsters  -- add Virtual Host Monster objects
+
+- Add Vocabularies  -- add Vocabulary objects (ZCatalog-related)
+
+- Add ZCatalogs  -- add ZCatalog objects
+
+- Add Zope Tutorials  -- add Zope Tutorial objects
+
+- Change DTML Documents -- modify DTML Documents
+
+- Change DTML Methods  -- modify DTML Methods
+
+- Change Database Connections  -- change database connection objects
+
+- Change Database Methods  -- change ZSQL method objects
+
+- Change External Methods -- change External Method objects
+
+- Change Images and Files  -- change Image and File objects
+
+- Change Python Scripts  -- change Python Script objects
+
+- Change Versions  -- change Version objects
+
+- Change bindings  -- change bindings (for Python Scripts)
+
+- Change cache managers  -- change cache manager objects
+
+- Change cache settings  -- change cache settings (cache mgr parameters)
+
+- Change configuration  -- generic
+
+- Change permissions  -- change permissions
+
+- Change proxy roles  -- change proxy roles
+
+- Create class instances  -- used for ZClass permission mappings
+
+- Delete objects  -- delete objects
+
+- Edit Factories  -- edit Factory objects (ZClass)
+
+- FTP access  -- allow FTP access to this object
+
+- Import/Export objects  -- export and import objects
+
+- Join/leave Versions  -- join and leave Zope versions
+
+- Manage Access Rules -- manage access rule objects
+
+- Manage Vocabulary  -- manage Vocabulary objects
+
+- Manage Z Classes  -- Manage ZClass objects (in the control panel)
+
+- Manage ZCatalog Entries  -- catalog and uncatalog objects
+
+- Manage properties -- manage properties of an object
+
+- Manage users  -- manage Zope users
+
+- Open/Close Database Connections  -- open and close database connections    
+
+- Query Vocabulary -- query Vocabulary objects (ZCatalog-related)
+
+- Save/discard Version changes -- save or discard Zope version changes
+
+- Search ZCatalog -- search a ZCatalog instance
+
+- Take ownership  -- take ownership of an object
+
+- Test Database Connections  -- test database connection objects
+
+- Undo changes  -- undo changes to the ZODB (e.g. use the Undo tab)
+
+- Use Database Methods  -- use ZSQL methods
+
+- Use Factories  -- use Factory objects (ZClass-related)
+
+- Use mailhost services -- use MailHost object services
+
+- View -- view or execute an object
+
+- View History -- view ZODB history of an object
+
+- View management screens -- view management screens related to an object

Copied: zope2docs/branches/baijum-reorganize/zdgbook/ComponentsAndInterfaces.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/ComponentsAndInterfaces.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/ComponentsAndInterfaces.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/ComponentsAndInterfaces.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,333 @@
+#########################
+Components and Interfaces
+#########################
+
+Zope uses a component architecture internally in many places.  Zope
+components is nothing but Python objects with interfaces that
+describe them.  As a Zope developer you can use interfaces right now
+to build your Zope components.
+
+Zope Components
+===============
+
+Components are objects that are associated with interfaces.  An
+interface is a Python object that describes how you work with other
+Python objects.  In this chapter, you'll see some simple examples of
+creating components, and a description of interfaces and how they
+work.
+
+Here is a very simple component that says hello.  Like all
+components, this one generally consists of two pieces, an interface,
+and an implementation::
+
+  from zope.interface import Interface
+  from zope.interface import implements
+
+  class IHello(Interface):
+      """The Hello interface provides greetings."""
+
+      def hello(name):
+          """Say hello to the name"""
+
+  class HelloComponent(object):
+
+      implements(IHello)
+
+      def hello(self, name):
+          return "hello %s!" % name
+
+Let's take a look at this step by step.  Here, you see two Python
+class statements.  The first class statement creates the *interface*,
+and the second class statement creates the *implementation*.
+
+The first class statement creates the ``IHello`` interface.  This
+interface describes one method, called ``hello``.  Notice that there
+is no implementation for this method, interfaces do not define
+behavior, they just describe a specification.
+
+The second ``class`` statement creates the ``HelloComponent`` class.
+This class is the actual component that *does* what ``IHello``
+*describes*.  This is usually referred to as the *implementation* of
+``IHello``.  In order for you to know what interfaces
+``HelloComponent`` implements, it must somehow associate itself with
+an interface.  The ``implements`` function call inside the class does
+just that.  It says, "I implement these interfaces".  In this case,
+``HelloComponent`` asserts that it implements one interface,
+``IHello``.
+
+The interface describes how you would work with the object, but it
+doesn't dictate how that description is implemented.  For example,
+here's a more complex implementation of the ``Hello`` interface::
+
+  import xmlrpclib
+  class XMLRPCHello:
+
+      implementats(IHello)
+
+      def hello(self, name):
+          """Delegates the hello call to a remote object
+          using XML-RPC.
+
+          """
+          s = xmlrpclib.Server('http://www.zope.org/')
+          return s.hello(name)
+
+This component contacts a remote server and gets its hello greeting
+from a remote component.
+
+And that's all there is to components, really.  The rest of this
+chapter describes interfaces and how you can work with them from the
+perspective of components.  In Chapter 3, we'll put all this together
+into a Zope product.
+
+Python Interfaces
+=================
+
+Interface describe the behavior of an object by containing useful
+information about the object.  This information includes:
+
+- Prose documentation about the object.  In Python terms, this is
+  called the "doc string" of the interface.  In this element, you
+  describe how the object works in prose language and any other
+  useful information about the object.
+
+- Descriptions of attributes.  Attribute descriptions include the
+  name of the attribute and prose documentation describing the
+  attributes usage.
+
+- Descriptions of methods.  Method descriptions can include:
+
+  - Prose "doc string" documentation about the method and its usage.
+
+  - A sequence of parameter objects that describes the parameters
+    expected by the method.
+
+- Optional tagged data.  Interface objects (and their attributes,
+  methods, and method parameters) can have optional, application
+  specific tagged data associated with them.  Examples uses for this
+  are security assertions, pre/post conditions, unit tests, and other
+  possible information you may want to associate with an Interface or
+  its attributes.
+
+Not all of this information is mandatory.  For example, you may only
+want the methods of your interface to have prose documentation and
+not describe the arguments of the method in exact detail.  Interface
+objects are flexible and let you give or take any of these
+components.
+
+Why Use Interfaces?
+===================
+
+Interfaces solve a number of problems that arise while developing
+large systems with lots of developers.
+
+- Developers waste a lot of time looking at the source code of your
+  system to figure out how objects work.  This is even worse if
+  someone else has already wasted their time doing the same thing.
+
+- Developers who are new to your system may misunderstand how your
+  object works, causing, and possibly propagating, usage errors.
+
+- Because an object's interface is inferred from the source,
+  developers may end up using methods and attributes that are meant
+  for "internal use only".
+
+- Code inspection can be hard, and very discouraging to novice
+  programmers trying to understand code written by gurus.
+
+Interfaces try to solve these problems by providing a way for you to
+describe how to use an object, and a mechanism for discovering that
+description.
+
+Creating Interfaces                                       
+===================
+
+The first step to creating a component, as you've been shown, is to
+create an interface.
+
+Interface objects can be conveniently constructed using the Python
+``class`` statement.  Keep in mind that this syntax can be a little
+misleading, because interfaces are *not* classes.  It is important to
+understand that using Python's class syntax is just a convenience,
+and that the resulting object is an *interface*, not a class.
+
+To create an interface object using Python's class syntax, create a
+Python class that subclasses from ``zope.interface.Interface``::
+
+  from zope.interface import Interface
+
+  class IHello(Interface):
+
+      def hello(name):
+          """Say hello to the world"""
+
+This interface does not implement behavior for its methods, it just
+describes an interface that a typical "Hello" object would realize.
+By subclassing the ``zope.interface.Interface`` interface, the
+resulting object ``Hello`` is an interface object. The Python
+interpreter confirms this::
+
+  >>> IHello
+  <InterfaceClass __main__.IHello>
+
+Now, you can associate the ``Hello`` Interface with your new concrete
+class in which you define your user behavior.  For example::
+
+  class HelloComponent:
+
+      implements(IHello)
+
+      def hello(self, name):
+          return "Hello %s!" % name
+
+This new class, ``HelloComponent`` is a concrete class that
+implements the ``Hello`` interface.  A class can realize more than
+one interface.  For example, say you had an interface called 'Item'
+that described how an object worked as an item in a "Container"
+object.  If you wanted to assert that ``HelloComponent`` instances
+realized the ``Item`` interface as well as ``Hello``, you can provide
+a sequence of Interface objects to the 'HelloComponent' class::
+
+  class HelloComponent:
+
+      implements(IHello, IItem)
+
+
+The Interface Model
+===================
+
+Interfaces can extend other interfaces.  For example, let's extend
+the ``IHello`` interface by adding an additional method::
+
+  class ISmartHello(IHello):
+      """A Hello object that remembers who it's greeted"""
+
+      def lastGreeted(self):
+          """Returns the name of the last person greeted."""
+
+
+``ISmartHello`` extends the ``IHello`` interface.  It does this by
+using the same syntax a class would use to subclass another class.
+
+Now, you can ask the ``ISmartHello`` for a list of the interfaces it
+extends with ``getBases``::
+
+  >>> ISmartHello.getBases()
+  (<InterfaceClass __main__.IHello>,)
+
+An interface can extend any number of other interfaces, and
+``getBases`` will return that list of interfaces for you.  If you
+want to know if ``ISmartHello`` extends any other interface, you
+could call ``getBases`` and search through the list, but a
+convenience method called ``extends`` is provided that returns true
+or false for this purpose::
+
+  >>> ISmartHello.extends(IHello)
+  True
+  >>> ISandwich(Interface):
+  ...     pass
+  >>> ISmartHello.extends(ISandwich)
+  False
+
+Here you can see ``extends`` can be used to determine if one
+interface extends another.
+
+You may notice a similarity between interfaces extending from other
+interfaces and classes sub-classing from other classes.  This *is* a
+similar concept, but the two should not be considered equal.  There
+is no assumption that classes and interfaces exist in a one to one
+relationship; one class may implement several interfaces, and a class
+may not implement its base classes's interfaces.
+
+The distinction between a class and an interface should always be
+kept clear.  The purpose of a class is to share the implementation of
+how an object works.  The purpose of an interface is to document how
+to work *with* an object, not how the object is implemented.  It is
+possible to have several different classes with very different
+implementations realize the same interface.  Because of this,
+interfaces and classes should never be confused.
+
+
+Querying an Interface
+=====================
+
+Interfaces can be queried for information.  The simplest case is to
+ask an interface the names of all the various interface items it
+describes.  From the Python interpreter, for example, you can walk
+right up to an interface and ask it for its *names*::
+
+  >>> User.names()
+  ['getUserName', 'getFavoriteColor', 'getPassword']
+
+Interfaces can also give you more interesting information about their
+items.  Interface objects can return a list of '(name, description)'
+tuples about their items by calling the *namesAndDescriptions*
+method.
+
+For example::
+
+  >>> User.namesAndDescriptions()
+  [('getUserName', <Interface.Method.Method object at 80f38f0>),
+  ('getFavoriteColor', <Interface.Method.Method object at 80b24f0>),
+  ('getPassword', <Interface.Method.Method object at 80fded8>)]
+
+As you can see, the "description" of the Interface's three items in
+these cases are all `Method` objects.  Description objects can be
+either 'Attribute' or `Method` objects.  Attributes, methods, and
+interface objects implement the following interface::
+
+- `getName()` -- Returns the name of the object.
+
+- `getDoc()` -- Returns the documentation for the object.
+
+Method objects provide a way to describe rich meta-data about Python
+methods. Method objects have the following methods:
+
+- `getSignatureInfo()` -- Returns a dictionary describing the method
+  parameters.
+
+- `getSignatureString()` -- Returns a human-readable string
+  representation of the method's signature.
+
+For example::
+
+  >>> m = User.namesAndDescriptions()[0][1]
+  >>> m
+  <Interface.Method.Method object at 80f38f0>
+  >>> m.getSignatureString()
+  '(fullName=1)'
+  >>> m.getSignatureInfo()   
+  {'varargs': None, 'kwargs': None, 'optional': {'fullName': 1}, 
+  'required': (), 'positional': ('fullName',)}  
+
+You can use `getSignatureInfo` to find out the names and types of the
+method parameters.
+
+
+Checking Implementation
+=======================
+
+You can ask an interface if a certain class or instance that you hand
+it implements that interface.  For example, say you want to know if
+instances of the `HelloComponent` class implement 'Hello'::
+
+  IHello.implementedBy(HelloComponent)
+
+This is a true expression.  If you had an instance of
+`HelloComponent`, you can also ask the interface if that instance
+implements the interface::
+
+  IHello.implementedBy(my_hello_instance)
+
+This would also return true if *my_hello_instance* was an instance of
+*HelloComponent*, or any other class that implemented the *Hello*
+Interface.
+
+Conclusion
+==========
+
+Interfaces provide a simple way to describe your Python objects.  By
+using interfaces you document capabilities of objects.  As Zope
+becomes more component oriented, your objects will fit right in.
+While components and interfaces are forward looking technologies,
+they are useful today for documentation and verification.

Copied: zope2docs/branches/baijum-reorganize/zdgbook/Credits.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/Credits.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/Credits.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/Credits.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,13 @@
+#######
+Credits
+#######
+
+- Amos Latteier
+
+- Michel Pelletier
+
+- Shane Hathaway
+
+- Chris McDonough
+
+- Beehive

Copied: zope2docs/branches/baijum-reorganize/zdgbook/GettingStarted.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/GettingStarted.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/GettingStarted.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/GettingStarted.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,372 @@
+###############
+Getting Started
+###############
+
+Introduction
+============
+
+This chapter cover installation and getting started with development
+of a simple application.  This guide use a build system called
+`Buildout <http://www.buildout.org>`_ to build the application.  And
+the Python packages developed as part of the application can be
+distributed as `Python eggs
+<http://peak.telecommunity.com/DevCenter/setuptools>`_.
+
+
+Directory Structure
+===================
+
+To begin the application development, create a directory structure to
+place Python packages and build related files.
+
+::
+
+  $ mkdir poll
+  $ mkdir poll/poll_build
+  $ mkdir poll/poll.main
+
+All build related files can be added inside `poll_build` directory.
+The main Python package can be added inside `poll.main` directory.
+We can make the ``poll``, a namespace package using the functionality
+provided by `pkg_resources` module included in setuptools.
+
+Bootstraping the Build
+======================
+
+You should have Python 2.5 or 2.6 installed in your system.  To start
+the build process, download and run `bootstrap.py`.  The
+`bootstrap.py` will download and install `setuptools` and
+`zc.buildout` packages.  Also it will create the directory structure
+and `buildout` script inside `bin` directory.
+
+::
+
+  $ cd poll/poll.build
+  $ touch buildout.cfg
+  $ wget -c http://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap/bootstrap.py
+  $ python2.6 bootstrap.py
+
+Installing Zope 2
+=================
+
+From Zope 2.12 onwards Zope 2 is distributed in egg format.  To
+install Zope 2 egg and create an instance, update buildout
+configuration file (``buildout.cfg``) with appropriate parts and
+recipes.
+
+::
+
+  [buildout]
+  parts = zope2
+          instance
+  extends = http://download.zope.org/Zope2/index/2.12.0/versions.cfg
+
+  [zope2]
+  recipe = zc.recipe.egg
+  eggs = Zope2
+  interpreter = zopepy
+
+  [instance]
+  recipe = plone.recipe.zope2instance
+  user = admin:admin
+  http-address = 8080
+  eggs = ${zope2:eggs}
+
+The ``[zope2]`` part use `zc.recipe.egg` which will download `Zope2`
+egg and all its dependencies.  It will create few console scripts
+inside `bin` directory.  Also it will create a custom Python
+interpreter named ``zopepy``.
+
+The ``[instance]`` part creates a Zope 2 application instance to
+develop application.  It will create a script named ``instance``
+inside `bin` directory.  We can use that script to run the
+application instance.
+
+After updating the buildout configuration, you can run the `buildout`
+command to build the system.
+
+::
+
+  $ ./bin/buildout
+
+The initial build will take some time to complete.
+
+Running Instance
+================
+
+Once build is completed, you can run Zope 2 instance like this.
+
+::
+
+  $ ./bin/instance fg
+
+
+You can see that Zope is running in 8080 port.  You can go to the
+Zope Management Interface (ZMI).
+
+::
+
+  http://localhost:8080/manage
+
+You can provide the user name & password provided in `[instance]`
+part to access this page.
+
+You can see a list of installable applications in the drop-down box.
+Also you can see it in "Control_Panel" -> "Products".
+
+::
+
+  http://localhost:8080/Control_Panel/Products/manage_main
+
+In the next section we will make the `poll.main` listed here.  And
+later we will make it installable.
+
+
+Developing the main package
+===========================
+
+Now we can move to `poll.main` packae to create the main package to
+develop the application.  We can develop the entire application
+inside `poll.main` package.  But it is reccomended to split packages
+logically and maintain the dependencies between packages properly.
+
+::
+
+  $ cd ../poll.build
+
+Again we need to create the basic directory structure and `setup.py`
+to create egg distribution.  We are going to place python package
+inside `src` directory.
+
+::
+
+  $ touch setup.py
+  $ mkdir src
+  $ mkdir src/poll
+  $ mkdir src/poll/main
+  $ touch src/poll/__init__.py
+  $ touch src/poll/main/__init__.py
+  $ touch src/poll/main/configure.zcml
+
+The last file we created is a configuration file called Zope
+Configuration Markup Language (ZCML). Soon we will add some boiler
+plate code inside ZCML file.
+
+To declare `poll` as a namespace package, we need to add this boiler
+plate code to `src/poll/__init__.py`.
+
+::
+
+  __import__('pkg_resources').declare_namespace(__name__)
+
+Next we need to add the minimum meta data required for the package in
+`setup.py`.
+
+::
+
+  from setuptools import setup, find_packages
+
+  setup(
+      name="poll.main",
+      version="0.1",
+      packages=find_packages("src"),
+      package_dir={"": "src"},
+      namespace_packages=["poll"],
+      install_requires=["setuptools",
+                        "Zope2"],
+      )
+
+We need to add two more files to be recognized by Zope.  First,
+define this call-back function in `src/poll/main/__init__.py`.
+
+::
+
+  def initialize(registrar):
+      pass
+
+And in the ZCML file add these few lines.
+
+::
+
+  <configure
+      xmlns="http://namespaces.zope.org/five">
+
+      <registerPackage package="." initialize=".initialize" />
+
+  </configure>
+
+Creating Installable Application
+================================
+
+We need three things to make an installable application.
+
+- Form object created using ZPT (manage_addPollMain)
+- A function to define form action (addPollMain)
+- A class to define toplevel application object (PollMain).
+
+And we need to register the class along with form and add function
+using the `registrar` object passed to the `initialize` function.
+
+We can define all these things in `app.py` and the form template as
+`manage_addPollMain_form.zpt`.
+
+::
+
+  $ touch src/poll/main/app.py
+  $ touch src/poll/main/manage_addPollMain_form.zpt
+
+Here is the code for `app.py`.
+
+::
+
+  from OFS.Folder import Folder
+  from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+  class PollMain(Folder):
+      meta_type = "POLL"
+
+  manage_addPollMain = PageTemplateFile("manage_addPollMain_form", globals())
+
+  def addPollMain(context, id):
+      """ """
+      context._setObject(id, PollMain(id))
+      return "POLL Installed: %s" % id
+
+And `manage_addPollMain_form.zpt`.
+
+::
+
+  <html xmlns="http://www.w3.org/1999/xhtml"
+        xmlns:tal="http://xml.zope.org/namespaces/tal">
+    <body>
+
+      <h2>Add POLL</h2>
+      <form action="addPollMain" method="post">
+        Id: <input type="text" name="id" /><br />
+        Title: <input type="text" name="title" /><br />
+        <input type="submit" value="Add" />
+      </form>
+    </body>
+  </html>
+
+Finally we can register it like this (update `__init__.py`)::
+
+  from poll.main.app import PollMain, manage_addPollMain, addPollMain
+
+  def initialize(registrar):
+      registrar.registerClass(PollMain,
+                              constructors=(manage_addPollMain, addPollMain))
+
+The application is now ready to install.  But we need to make some
+changes in `poll_build` to recognize this package by Zope 2.
+
+Adding poll.main to build
+=========================
+
+First in `[buildout]` part we need to mention that `poll.main` is
+locally developed.  Otherwise buildout will try to get the package
+from package index server, by default http://pypi.python.org/pypi .
+
+::
+
+  [buildout]
+  develop = ../poll.main
+  ...
+
+Also we need to add `poll.main` egg to `eggs` option in `[zope2]`
+part.
+
+::
+
+  ...
+  eggs = Zope2
+         poll.main
+  ...
+
+And finally we need to add a new option to include the ZCML file.  So
+that the package will be recognized by Zope.
+
+::
+
+  ...
+  zcml = poll.main
+
+The final `buildout.cfg` will look like this.
+
+::
+
+  [buildout]
+  develop = ../poll.main
+  parts = zope2
+          instance
+
+  [zope2]
+  recipe = zc.recipe.egg
+  eggs = Zope2
+         poll.main
+  interpreter = zopepy
+
+  [instance]
+  recipe = plone.recipe.zope2instance
+  user = admin:admin
+  http-address = 8080
+  eggs = ${zope2:eggs}
+  zcml = poll.main
+
+Now to make these change effective, run the buildout again.
+
+::
+
+  $ ./bin/buildout
+
+Now we can run application instance again.
+
+::
+
+  $ ./bin/instance fg
+
+Adding application instance
+===========================
+
+Visit ZMI and select `POLL` from the drop-down box.  It will display
+the add-form created earlier.  You can provide the ID as `poll` and
+submit the form.  After submitting, it should display a message:
+"POLL Installed: poll".
+
+Adding the main page to POLL
+============================
+
+In this section we will try to add a main page to POLL application.
+So that we can acces POLL application like this:
+http://localhost:8080/poll .
+
+First create a file named `index_html.zpt` inside `src/poll/main` with
+content like this::
+
+  <html>
+  <head>
+    <title>Welcome to POLL!</title>
+  </head>
+  <body>
+
+  <h2>Welcome to POLL!</h2>
+
+  </body>
+  </html>
+
+Now add an attribute named `index_html` inside PollMain class like
+this::
+
+  class PollMain(Folder):
+      meta_type = "POLL"
+
+      index_html = PageTemplateFile("index_html", globals())
+
+Restart the Zope. Now you can see that it display the main page when
+you access: http://localhost:8080/poll .
+
+Summary
+=======
+
+This chapter covered installation and beginning a simple project in
+Zope 2.

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.stx
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.stx	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.stx	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,169 +0,0 @@
-Here is the place to add comments about "gotchas" related to Zope development.  We will try to work
-these in to the ZDG narrative from time to time.
-
-  % mcdonc - Jan. 17, 2002 6:23 pm - Methods declared in Product classes must
-    have docstrings to callable by visiting them "through the web" (by calling
-    them up by URL via a browser).
-
-  % Anonymous User - Feb. 27, 2002 10:52 pm - Volatile attributes are not shared
-    between threads, so using them for  page counters or holding state between
-    requests will not work (although it will sometimes appear to until your server
-    is under load)
-
-  % Anonymous User - May 22, 2002 7:18 am:
-   DTMLMethod with a name ending '_alpha' was not rendered at all
-
-  % Anonymous User - July 17, 2002 1:40 pm:
-   From Zope Maillist:
-   On Tue, 16 Jul 2002, Ross Boylan wrote:
-   > The Zope Developer's Guide and the API docs (Zope 2.5) present
-   > different stories about how to add things to object managers.  I don't
-   > really follow what the API stuff is doing.  This is a request for
-   > clarification.
-   >
-   > Devguide says do
-   > def addFunction(dispatcher, id):
-   >    "Create object and add to self"
-   >    p = SomeProduct(id)
-   >    dispatcher.Destination()._setObject(id, p)
-   >
-   > This makes sense, though, as commented at
-   > http://www.zope.org//Members/michel/Projects/Interfaces/ObjectManager,
-   > it relies on a private, undocumented method.  addFunction is in outer
-   > scope of a module, and is hooked up wtih various calls in ___init__.py.
-   Call this the "add function".  Defined by the product, it is passed
-   the dispatcher for the ObjectManager to which the object is being added.
-   As you say, it apparently uses a private function, however despite
-   it's (historical artifact of a) name, it is the proper way to do
-   this operation.  And it is documented, in the Dev Guide <wry grin>.
-   > On the other hand, the ObjectManager API says to do
-   > self.manage_addProduct['OFSP'].manage_addFolder(id, title).
-   This is the action that non-Product code uses to add an object from
-   the Product to an arbitrary object manager.  'self' being the object
-   manager in question (eg: when called from an External Method, self
-   will be the folder the External Method was called on).  This sequence
-   *calls* the "add function" defined above.  In this case, it is
-   calling the add function defined by the Folder object in the OFSP
-   Product.
-   > First, what scope should that be done in?  Second, this seems to
-   > create one product (OFSP) and then add a folder to it, so that it
-   > creates two, nested products.
-   Actually, it doesn't.  This syntax has bothered me since I first
-   encoutered it, and I'm sure I'm not alone.  But we are stuck with
-   it (for now).  "manage_addProduct[<someproductname>]" is, essentially,
-   a lookup in a registry keyed by product name.  So that part looks
-   up the Product from the registry, and then you have access to the
-   module level functions in that Product, such as the "add function"
-   defined above.
-   > The API for Folder mentions manage_addFolder as a constructor, but
-   > again the scope is unclear to me.  Presumably it needs to know what to
-   > add it to, but that is not passed in.
-   You are calling the method on 'self' in the API example, or on some
-   other reference to an ObjectManager in some other context.
-   (Literally 'context' if you were doing this from a pythonscript.)
-   'manage_addProduct' gets "acquired" (from where I'm not quite sure
-   <wry grin>), and some magic that I haven't had a need to look in
-   to arranges things so that your add function gets passed a dispatcher
-   that has that ObjectManager as its Destination() as its first
-   argument, followed by whatever arguments (id, title) in the API
-   example) you pass it explicitly.  This is an example of Zope2
-   "magic" that we are trying hard to eliminate from Zope3 <grin>.
-   > Finally, the use of id in two places in the first code snippet (one
-   > apparently associated with the container, the other with the object)
-   > seems like an invitation to trouble.  Why is it done that way?
-   Tell us about it.  This is an old Zope2 (or was it bobo?) design
-   decision that has been revisited in Zope3.  In Zope3, only containers
-   know about ids in the general case, not the objects referenced by
-   them.
-   > One reason I want to know this is that I'm considering having a
-   > container that would automatically label (or set id) of its contents
-   > (e.g., 'a' is first, 'b' is second....).
-   >
-   > Thanks for any light you can shed.
-   Hopefully I haven't told you anything untrue up above, but if I have
-   someone will doubtless correct me <grin>.
-   --RDM
-
-  % eckamm - Nov. 11, 2002 10:05 pm:
-   This one has bit me on more than one occassion:
-       manage_add_XYZ_form = DTMLFile('dtml/manage_add_XYZ_form')
-   instead of:
-       manage_add_XYZ_form = DTMLFile('dtml/manage_add_XYZ_form', globals())
-   The error message is tough to interpret; it looks like an attempt
-   is made to find manage_add_XYZ_form.dtml in {base}/lib/python/dtml/.
-   This may send you on a wild goose chase if you're like me.
-
-  % slinkp - Mar. 21, 2003 12:53 pm:
-   i just posted this to the zope list...
-   I find "Monkey patches" a useful way to expand or modify functionality provided by
-   zope or 3rd-party products, but I just discovered something very important:
-   it's apparently NOT safe to "refresh" a MonkeyPatch-style product.
-   I have a monkeypatch that works fine until I refresh it, then I get mysterious
-   errors like "Object of type 'None' is not callable" with no indication in the
-   traceback of what object is None or even what's trying to call it!
-   I've spent hours in a debugging session trying to find out what's None and
-   came up with nothing.
-   Then i discovered that if i restart zope, everything's fine. :-P
-
-  % Anonymous User - Mar. 29, 2003 12:43 am:
-   slinkp: Yes, that's right, you should never try to refresh monkey patch
-   products. However, I haven't found the right way to spread this warning
-   so that the people who need to know it will hear it. How do you suggest
-   this be documented?
-   Shane Hathaway
-
-  % Anonymous User - Aug. 5, 2003 4:51 pm:
-   Seems obvious to some, but wansn't obvious to me:
-   ZCatalog method searchResults' sort_limit argument only works when sort_on
-   argument is present as well. A "nice to have" would be to limit unsorted
-   results coming back from the catalog as opposed to doing it after the fact.
-
-  % slinkp - Dec. 8, 2003 3:32 pm:
-   Don't confuse paths and URLs. Specifically, avoid using absolute_url(1) or path variables from REQUEST when
-   constructing paths that will be fed to restrictedTraverse() or similar. Everything works fine until virtual
-   hosting comes into play, at which point some part of your path may be meaningful to the client but not
-   correspond to any object in Zope. This can lead to much hair-tearing when your working app suddenly breaks at
-   deployment time. Solution: if you need to fiddle with paths, use '/'.join(foo.getPhysicalPath()) instead.
-   This is unaffected by virtual hosting.
-   The behavior of absolute_url(1) *may* change in zope 2.7 or later, we're still arguing about it :-)
-
-  % slinkp - Jan. 24, 2004 6:26 pm:
-   Set self._p_changed=1  *before* mutating something, not after.
-   From Steve Alexander on the zodb-dev mailing list:
-   > The reason to set _p_changed before mutating the object is because if
-   > there is an exception raised after a mutation but before setting
-   > _p_changed, your persistnent object might stay around in the cache. That
-   > is, it would not be reloaded with fresh state.
-   >
-   > Consider this example:
-   >
-   >      def storeMany(self, keys, values):
-   >          for key, value in zip(keys, values):
-   >              self.bar[key] = value
-   >          self._p_changed = 1  # This is too late!
-   >
-   > What happens if I call the method as below?
-   >
-   >   obj.storeMany(['fish', {}, 'fluid'], [6, 28, 496])
-   >
-   > The method will raise a TypeError because dicts are unhashable. However,
-   > the entry 'fish': 6 will have been added to the dict. The ZODB will not
-   > realize that the object has effectively changed, so the object can stick
-   > around in the cache.
-   Personally, I now prefer to avoid directly touching self._p_changed when possible:
-   1) as the zdg says, it isn't necessary for immutables.
-   2) for mutables, many cases can be covered by BTrees, PersistentLists, and
-   PersistentMappings which are very kindly provided by ZODB, so we should
-   use them :-)
-
-  % slinkp - Apr. 18, 2005 9:59 am:
-   ComputedAttributes are not documented by the ZDG, and they should be.
-
-  % slinkp - Apr. 18, 2005 10:32 am:
-   I just added some ComputedAttribute doc at http://zopewiki.org/ComputedAttribute,
-   feel free to copy this for next version of ZDG.
-
-  % Anonymous User - Aug. 19, 2005 6:24 pm:
-   Make sure that your classes inherit from Acquisition.Implicit or Acquisition.Explicit. In mid-development I
-   thought that was probably unnecessary and deleted that base class, which later caused objects I added to not
-   acquire the security information needed, leaving me unable to manage those objects.

Copied: zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.txt (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.stx)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.txt	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/Gotchas.txt	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,169 @@
+Here is the place to add comments about "gotchas" related to Zope development.  We will try to work
+these in to the ZDG narrative from time to time.
+
+  % mcdonc - Jan. 17, 2002 6:23 pm - Methods declared in Product classes must
+    have docstrings to callable by visiting them "through the web" (by calling
+    them up by URL via a browser).
+
+  % Anonymous User - Feb. 27, 2002 10:52 pm - Volatile attributes are not shared
+    between threads, so using them for  page counters or holding state between
+    requests will not work (although it will sometimes appear to until your server
+    is under load)
+
+  % Anonymous User - May 22, 2002 7:18 am:
+   DTMLMethod with a name ending '_alpha' was not rendered at all
+
+  % Anonymous User - July 17, 2002 1:40 pm:
+   From Zope Maillist:
+   On Tue, 16 Jul 2002, Ross Boylan wrote:
+   > The Zope Developer's Guide and the API docs (Zope 2.5) present
+   > different stories about how to add things to object managers.  I don't
+   > really follow what the API stuff is doing.  This is a request for
+   > clarification.
+   >
+   > Devguide says do
+   > def addFunction(dispatcher, id):
+   >    "Create object and add to self"
+   >    p = SomeProduct(id)
+   >    dispatcher.Destination()._setObject(id, p)
+   >
+   > This makes sense, though, as commented at
+   > http://www.zope.org//Members/michel/Projects/Interfaces/ObjectManager,
+   > it relies on a private, undocumented method.  addFunction is in outer
+   > scope of a module, and is hooked up wtih various calls in ___init__.py.
+   Call this the "add function".  Defined by the product, it is passed
+   the dispatcher for the ObjectManager to which the object is being added.
+   As you say, it apparently uses a private function, however despite
+   it's (historical artifact of a) name, it is the proper way to do
+   this operation.  And it is documented, in the Dev Guide <wry grin>.
+   > On the other hand, the ObjectManager API says to do
+   > self.manage_addProduct['OFSP'].manage_addFolder(id, title).
+   This is the action that non-Product code uses to add an object from
+   the Product to an arbitrary object manager.  'self' being the object
+   manager in question (eg: when called from an External Method, self
+   will be the folder the External Method was called on).  This sequence
+   *calls* the "add function" defined above.  In this case, it is
+   calling the add function defined by the Folder object in the OFSP
+   Product.
+   > First, what scope should that be done in?  Second, this seems to
+   > create one product (OFSP) and then add a folder to it, so that it
+   > creates two, nested products.
+   Actually, it doesn't.  This syntax has bothered me since I first
+   encoutered it, and I'm sure I'm not alone.  But we are stuck with
+   it (for now).  "manage_addProduct[<someproductname>]" is, essentially,
+   a lookup in a registry keyed by product name.  So that part looks
+   up the Product from the registry, and then you have access to the
+   module level functions in that Product, such as the "add function"
+   defined above.
+   > The API for Folder mentions manage_addFolder as a constructor, but
+   > again the scope is unclear to me.  Presumably it needs to know what to
+   > add it to, but that is not passed in.
+   You are calling the method on 'self' in the API example, or on some
+   other reference to an ObjectManager in some other context.
+   (Literally 'context' if you were doing this from a pythonscript.)
+   'manage_addProduct' gets "acquired" (from where I'm not quite sure
+   <wry grin>), and some magic that I haven't had a need to look in
+   to arranges things so that your add function gets passed a dispatcher
+   that has that ObjectManager as its Destination() as its first
+   argument, followed by whatever arguments (id, title) in the API
+   example) you pass it explicitly.  This is an example of Zope2
+   "magic" that we are trying hard to eliminate from Zope3 <grin>.
+   > Finally, the use of id in two places in the first code snippet (one
+   > apparently associated with the container, the other with the object)
+   > seems like an invitation to trouble.  Why is it done that way?
+   Tell us about it.  This is an old Zope2 (or was it bobo?) design
+   decision that has been revisited in Zope3.  In Zope3, only containers
+   know about ids in the general case, not the objects referenced by
+   them.
+   > One reason I want to know this is that I'm considering having a
+   > container that would automatically label (or set id) of its contents
+   > (e.g., 'a' is first, 'b' is second....).
+   >
+   > Thanks for any light you can shed.
+   Hopefully I haven't told you anything untrue up above, but if I have
+   someone will doubtless correct me <grin>.
+   --RDM
+
+  % eckamm - Nov. 11, 2002 10:05 pm:
+   This one has bit me on more than one occassion:
+       manage_add_XYZ_form = DTMLFile('dtml/manage_add_XYZ_form')
+   instead of:
+       manage_add_XYZ_form = DTMLFile('dtml/manage_add_XYZ_form', globals())
+   The error message is tough to interpret; it looks like an attempt
+   is made to find manage_add_XYZ_form.dtml in {base}/lib/python/dtml/.
+   This may send you on a wild goose chase if you're like me.
+
+  % slinkp - Mar. 21, 2003 12:53 pm:
+   i just posted this to the zope list...
+   I find "Monkey patches" a useful way to expand or modify functionality provided by
+   zope or 3rd-party products, but I just discovered something very important:
+   it's apparently NOT safe to "refresh" a MonkeyPatch-style product.
+   I have a monkeypatch that works fine until I refresh it, then I get mysterious
+   errors like "Object of type 'None' is not callable" with no indication in the
+   traceback of what object is None or even what's trying to call it!
+   I've spent hours in a debugging session trying to find out what's None and
+   came up with nothing.
+   Then i discovered that if i restart zope, everything's fine. :-P
+
+  % Anonymous User - Mar. 29, 2003 12:43 am:
+   slinkp: Yes, that's right, you should never try to refresh monkey patch
+   products. However, I haven't found the right way to spread this warning
+   so that the people who need to know it will hear it. How do you suggest
+   this be documented?
+   Shane Hathaway
+
+  % Anonymous User - Aug. 5, 2003 4:51 pm:
+   Seems obvious to some, but wansn't obvious to me:
+   ZCatalog method searchResults' sort_limit argument only works when sort_on
+   argument is present as well. A "nice to have" would be to limit unsorted
+   results coming back from the catalog as opposed to doing it after the fact.
+
+  % slinkp - Dec. 8, 2003 3:32 pm:
+   Don't confuse paths and URLs. Specifically, avoid using absolute_url(1) or path variables from REQUEST when
+   constructing paths that will be fed to restrictedTraverse() or similar. Everything works fine until virtual
+   hosting comes into play, at which point some part of your path may be meaningful to the client but not
+   correspond to any object in Zope. This can lead to much hair-tearing when your working app suddenly breaks at
+   deployment time. Solution: if you need to fiddle with paths, use '/'.join(foo.getPhysicalPath()) instead.
+   This is unaffected by virtual hosting.
+   The behavior of absolute_url(1) *may* change in zope 2.7 or later, we're still arguing about it :-)
+
+  % slinkp - Jan. 24, 2004 6:26 pm:
+   Set self._p_changed=1  *before* mutating something, not after.
+   From Steve Alexander on the zodb-dev mailing list:
+   > The reason to set _p_changed before mutating the object is because if
+   > there is an exception raised after a mutation but before setting
+   > _p_changed, your persistnent object might stay around in the cache. That
+   > is, it would not be reloaded with fresh state.
+   >
+   > Consider this example:
+   >
+   >      def storeMany(self, keys, values):
+   >          for key, value in zip(keys, values):
+   >              self.bar[key] = value
+   >          self._p_changed = 1  # This is too late!
+   >
+   > What happens if I call the method as below?
+   >
+   >   obj.storeMany(['fish', {}, 'fluid'], [6, 28, 496])
+   >
+   > The method will raise a TypeError because dicts are unhashable. However,
+   > the entry 'fish': 6 will have been added to the dict. The ZODB will not
+   > realize that the object has effectively changed, so the object can stick
+   > around in the cache.
+   Personally, I now prefer to avoid directly touching self._p_changed when possible:
+   1) as the zdg says, it isn't necessary for immutables.
+   2) for mutables, many cases can be covered by BTrees, PersistentLists, and
+   PersistentMappings which are very kindly provided by ZODB, so we should
+   use them :-)
+
+  % slinkp - Apr. 18, 2005 9:59 am:
+   ComputedAttributes are not documented by the ZDG, and they should be.
+
+  % slinkp - Apr. 18, 2005 10:32 am:
+   I just added some ComputedAttribute doc at http://zopewiki.org/ComputedAttribute,
+   feel free to copy this for next version of ZDG.
+
+  % Anonymous User - Aug. 19, 2005 6:24 pm:
+   Make sure that your classes inherit from Acquisition.Implicit or Acquisition.Explicit. In mid-development I
+   thought that was probably unnecessary and deleted that base class, which later caused objects I added to not
+   acquire the security information needed, leaving me unable to manage those objects.

Copied: zope2docs/branches/baijum-reorganize/zdgbook/Introduction.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/Introduction.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/Introduction.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/Introduction.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,97 @@
+############
+Introduction
+############
+
+Overview
+========
+
+Zope 2 is a free and open-source, object-oriented web application
+server written in the Python programming language.  The term ZOPE is
+an acronym for "Z Object Publishing Environment" (the Z doesn't
+really mean anything in particular).  However, nowadays ZOPE is
+simply written as Zope.  It has three distinct audiences.
+
+*Site Managers*
+  Individuals who use of Zope's "out of the box" features to build
+  websites.  This audience is interested in making use of Zope's
+  existing array of features to create content management solutions.
+  They will likely make heavy use of "through the web" scripting
+  using DTML, Page Templates, and Python Scripts as well as (of
+  course) HTML and XML.  They are generally less concerned about code
+  reuse than the speed with which they can create a custom
+  application or website.
+
+*Developers*
+  Individuals who wish to extend Zope to create highly customized
+  solutions.  This audience is likely interested in creating highly
+  reusable custom code that makes Zope do something new and
+  interesting.  They will likely make heavy use of "through the
+  file-system" style development.
+
+*Administrators*
+  Individuals responsible for keeping a Zope site running and
+  performing installations and upgrades.
+
+This guide is intended to document Zope for the second audience,
+Developers, as defined above.  If you fit more into the "user"
+audience defined above, you'll probably want to start by reading `The
+Zope Book <http://docs.zope.org/zope2book>`_ .  If you fit more into
+the "administrator" audience defined above, you'll likely be
+interested in `The Zope Administrator's Guide
+<http://www.zope.org/DocProjects/AdminGuide>`_, although it is
+currently unfinished.
+
+Throughout this guide, it is assumed that you know how to program in
+the Python programming language.  Most of the examples in this guide
+will be in Python.  There are a number of great resources and books
+for learning Python; the best online resource is the `python.org web
+site <http://www.python.org/>`_ and many books can be found on the
+shelves of your local bookstore.
+
+Organization of the book
+========================
+
+This book describes Zope's services to the developer from a hands on,
+example-oriented standpoint.  This book is not a complete reference
+to the Zope API, but rather a practical guide to applying Zope's
+services to develop and deploy your own web applications.  This book
+covers the following topics:
+
+*Getting Started*
+  This chapter provides a brief overview of installation and getting
+  started with application development.
+
+*Components and Interfaces*
+  Zope use a component-centric development model.  This chapter
+  describes the component model in Zope and how Zope components are
+  described through interfaces.
+
+*Object Publishing*
+  Developing applications for Zope involves more than just creating a
+  component, that component must be *publishable* on the web.  This
+  chapter describes publication, and how your components need to be
+  designed to be published.
+
+*Zope Products*
+  New Zope components are distributed and installed in packages
+  called "Products".  This chapter explains Products in detail.
+
+*Persistent Components*
+  Zope provides a built-in, transparent Python object database called
+  ZODB.  This chapter describes how to create persistent components,
+  and how they work in conjunction with the ZODB.
+
+*Acquisition*
+  Zope relies heavily on a dynamic technique called acquisition. This
+  chapter explores acquisition thoroughly.
+
+*Security*
+  When your component is used by many different people through the
+  web, security becomes a big concern.  This chapter describes Zope's
+  security API and how you can use it to make security assertions
+  about your object.
+
+*Debugging and Testing*
+  Zope has built in debugging and testing support.  This chapter
+  describes these facilities and how you can debug and test your
+  components.

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/Makefile
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/Makefile	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/Makefile	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,75 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
-PAPER         =
-
-# Internal variables.
-PAPEROPT_a4     = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS   = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
-
-.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
-
-help:
-	@echo "Please use \`make <target>' where <target> is one of"
-	@echo "  html      to make standalone HTML files"
-	@echo "  pickle    to make pickle files"
-	@echo "  json      to make JSON files"
-	@echo "  htmlhelp  to make HTML files and a HTML help project"
-	@echo "  latex     to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
-	@echo "  changes   to make an overview over all changed/added/deprecated items"
-	@echo "  linkcheck to check all external links for integrity"
-
-clean:
-	-rm -rf build/*
-
-html:
-	mkdir -p build/html build/doctrees
-	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
-	@echo
-	@echo "Build finished. The HTML pages are in build/html."
-
-pickle:
-	mkdir -p build/pickle build/doctrees
-	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle
-	@echo
-	@echo "Build finished; now you can process the pickle files."
-
-web: pickle
-
-json:
-	mkdir -p build/json build/doctrees
-	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) build/json
-	@echo
-	@echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
-	mkdir -p build/htmlhelp build/doctrees
-	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
-	@echo
-	@echo "Build finished; now you can run HTML Help Workshop with the" \
-	      ".hhp project file in build/htmlhelp."
-
-latex:
-	mkdir -p build/latex build/doctrees
-	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
-	@echo
-	@echo "Build finished; the LaTeX files are in build/latex."
-	@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
-	      "run these through (pdf)latex."
-
-changes:
-	mkdir -p build/changes build/doctrees
-	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
-	@echo
-	@echo "The overview file is in build/changes."
-
-linkcheck:
-	mkdir -p build/linkcheck build/doctrees
-	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
-	@echo
-	@echo "Link check complete; look for any errors in the above output " \
-	      "or in build/linkcheck/output.txt."

Copied: zope2docs/branches/baijum-reorganize/zdgbook/ObjectPublishing.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/ObjectPublishing.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/ObjectPublishing.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/ObjectPublishing.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,1297 @@
+#################
+Object Publishing
+#################
+
+Introduction
+============
+
+Zope puts your objects on the web. This is called *object
+publishing*. One of Zope's unique characteristics is the way it
+allows you to walk up to your objects and call methods on them with
+simple URLs.  In addition to HTTP, Zope makes your objects available
+to other network protocols including FTP, WebDAV and XML-RPC.
+
+
+In this chapter you'll find out exactly how Zope publishes
+objects. You'll learn all you need to know in order to design your
+objects for web publishing.
+
+ 
+HTTP Publishing
+===============
+
+When you contact Zope with a web browser, your browser sends an HTTP
+request to Zope's web server. After the request is completely
+received, it is processed by 'ZPublisher', which is Zope's object
+publisher. 'ZPublisher' is a kind of light-weight ORB (Object Request
+Broker). It takes the request and locates an object to handle the
+request. The publisher uses the request URL as a map to locate the
+published object. Finding an object to handle the request is called
+*traversal*, since the publisher moves from object to object as it
+looks for the right one. Once the published object is found, the
+publisher calls a method on the published object, passing it
+parameters as necessary.  The publisher uses information in the
+request to determine which method to call, and what parameters to
+pass. The process of extracting parameters from the request is called
+*argument marshalling*. The published object then returns a response,
+which is passed back to Zope's web server. The web server, then
+passes the response back to your web browser.
+
+
+The publishing process is summarized in [2-1]
+
+.. figure:: Figures/2-1.png
+
+   2.1 Object publishing
+
+
+Typically the published object is a persistent object that the
+published module loads from the ZODB.  See Chapter 4 for more
+information on the ZODB.
+
+
+This chapter will cover all the steps of object publishing in
+detail. To summarize, object publishing consists of the main steps:
+
+1. The client sends a request to the publisher
+
+2. The publisher locates the published object using the request
+   URL as a map.
+
+3. The publisher calls the published object with arguments from
+   the request.
+
+4. The publisher interprets and returns the results to the
+   client.
+
+The chapter will also cover all the technical details, special cases
+and extra-steps that this list glosses over.
+
+
+URL Traversal
+=============
+
+Traversal is the process the publisher uses to locate the published
+object. Typically the publisher locates the published object by
+walking along the URL. Take for example a collection of objects::
+
+      class Classification:
+          ...
+
+      class Animal:
+          ...
+
+          def screech(self, ...):
+              ...
+
+      vertebrates=Classification(...)
+      vertebrates.mammals=Classification(...)
+      vertebrates.reptiles=Classification(...)
+      vertebrates.mammals.monkey=Animal(...)
+      vertebrates.mammals.dog=Animal(...)
+      vertebrates.reptiles.lizard=Animal(...)
+
+
+This collection of objects forms an object hierarchy. Using Zope you
+can publish objects with URLs. For example, the URL
+'http://zope/vertebrates/mammals/monkey/screech', will traverse the
+object hierarchy, find the 'monkey' object and call its 'screech'
+method.
+
+.. figure:: Figures/2-2.png
+
+   2.2 Traversal path through an object hierarchy
+
+The publisher starts from the root object and takes each step in the
+URL as a key to locate the next object. It moves to the next object
+and continues to move from object to object using the URL as a guide.
+
+Typically the next object is a sub-object of the current object that
+is named by the path segment. So in the example above, when the
+publisher gets to the 'vertebrates' object, the next path segment is
+"mammals", and this tells the publisher to look for a sub-object of
+the current object with that name. Traversal stops when Zope comes to
+the end of the URL. If the final object is found, then it is
+published, otherwise an error is returned.
+
+
+Now let's take a more rigorous look at traversal.
+
+Traversal Interfaces
+====================
+
+Zope defines interfaces for publishable objects, and publishable
+modules.
+
+
+When you are developing for Zope you almost always use the 'Zope'
+package as your published module. However, if you are using
+'ZPublisher' outside of Zope you'll be interested in the published
+module interface.
+
+
+Publishable Object Requirements
+===============================
+
+Zope has few restrictions on publishable objects. The basic rule is
+that the object must have a doc string. This requirement goes for
+method objects too.
+
+Another requirement is that a publishable object must not have a name
+that begin with an underscore. These two restrictions are designed to
+keep private objects from being published.
+
+
+Finally, published objects cannot be Python module objects.
+
+Traversal Methods
+=================
+
+During traversal, 'ZPublisher' cuts the URL into path elements
+delimited by slashes, and uses each path element to traverse from the
+current object to the next object. 'ZPublisher' locates the next
+object in one of three ways:
+
+1. Using '__bobo_traverse__'
+
+2. Using 'getattr'
+
+3. Using dictionary access.
+
+First the publisher attempts to call the traversal hook method,
+'__bobo_traverse__'. If the current object has this method it is
+called with the request and the current path element. The method
+should return the next object or 'None' to indicate that a next
+object can't be found. You can also return a tuple of objects from
+'__bobo_traverse__' indicating a sequence of sub-objects. This allows
+you to add additional parent objects into the request. This is almost
+never necessary.
+
+
+Here's an example of how to use '__bobo_traverse__'::
+
+          def __bobo_traverse__(self, request, key):
+              # if there is a special cookie set, return special
+              # subobjects, otherwise return normal subobjects
+
+              if request.cookies.has_key('special'):
+                  # return a subobject from the special dict
+                  return self.special_subobjects.get(key, None)
+
+              # otherwise return a subobject from the normal dict
+              return self.normal_subobjects.get(key, None)
+
+
+This example shows how you can examine the request during the
+traversal process.
+
+If the current object does not define a '__bobo_traverse__'
+method, then the next object is searched for using 'getattr'.
+This locates sub-objects in the normal Python sense.
+
+If the next object can't be found with 'getattr', 'ZPublisher'
+calls on the current object as though it were a
+dictionary. Note: the path element will be a string, not an
+integer, so you cannot traverse sequences using index numbers
+in the URL.
+
+For example, suppose 'a' is the current object, and 'next' is
+the name of the path element. Here are the three things that
+'ZPublisher' will try in order to find the next object:
+
+  1. 'a.__bobo_traverse__("next")'
+
+  2. 'a.next'
+
+  3. 'a["next"]'
+
+
+Publishing Methods        
+==================
+
+Once the published object is located with traversal, Zope *publishes*
+it in one of three possible ways.
+
+- Calling the published object -- If the published object is a
+  function or method or other callable object, the publisher calls
+  it. Later in the chapter you'll find out how the publisher figures
+  out what arguments to pass when calling.
+
+- Calling the default method -- If the published object is not
+  callable, the publisher uses the default method. For HTTP 'GET' and
+  'POST' requests the default method is 'index_html'. For other HTTP
+  requests such as 'PUT' the publisher looks for a method named by
+  the HTTP method. So for an HTTP 'HEAD' request, the publisher would
+  call the 'HEAD' method on the published object.
+
+- Stringifying the published object -- If the published object isn't
+  callable, and doesn't have a default method, the publisher
+  publishes it using the Python 'str' function to turn it into a
+  string.
+
+
+After the response method has been determined and called, the
+publisher must interpret the results.
+
+Character Encodings for Responses
+=================================
+
+If the published method returns an object of type 'string', a plain
+8-bit character string, the publisher will use it directly as the
+body of the response.
+
+Things are different if the published method returns a unicode
+string, because the publisher has to apply some character
+encoding. The published method can choose which character encoding it
+uses by setting a 'Content-Type' response header which includes a
+'charset' property (setting response headers is explained later in
+this chapter). A common choice of character encoding is UTF-8. To
+cause the publisher to send unicode results as UTF-8 you need to set
+a 'Content-Type' header with the value 'text/html; charset=UTF-8'
+
+If the 'Content-Type' header does not include a charser property (or
+if this header has not been set by the published method) then the
+publisher will choose a default character encoding. Today this
+default is ISO-8859-1 (also known as Latin-1) for compatability with
+old versions of Zope which did not include Unicode support. At some
+time in the future this default is likely to change to UTF-8.
+
+HTTP Responses
+==============
+
+Normally the published method returns a string which is considered
+the body of the HTTP response. The response headers can be controlled
+by calling methods on the response object, which is described later
+in the chapter. Optionally, the published method can return a tuple
+with the title, and body of the response. In this case, the publisher
+returns an generated HTML page, with the first item of the tuple used
+for the HTML 'title' of the page, and the second item as the contents
+of the HTML 'body' tag. For example a response of::
+
+  ('response', 'the response')
+
+
+is turned into this HTML page::
+
+  <html>
+  <head><title>response</title></head>
+  <body>the response</body>
+  </html>
+
+Controlling Base HREF
+=====================
+
+When you publish an object that returns HTML relative links should
+allow you to navigate between methods. Consider this example::
+
+  class Example:
+      "example"
+
+      def one(self):
+          "method one"
+          return """<html>
+                    <head>
+                    <title>one</title>
+                    </head>
+                    <body>
+                    <a href="two">two</a> 
+                    </body>
+                    </html>"""
+
+      def two(self):
+          "method two"
+          return """<html>
+                    <head>
+                    <title>two</title>
+                    </head>
+                    <body>
+                    <a href="one">one</a> 
+                    </body>
+                    </html>"""
+
+
+However, the default method, 'index_html' presents a problem. Since
+you can access the 'index_html' method without specifying the method
+name in the URL, relative links returned by the 'index_html' method
+won't work right. For example::
+
+            class Example:
+                "example"
+
+                 def index_html(self):
+                    return """<html>
+                              <head>
+                              <title>one</title>
+                              </head>
+                              <body>
+                              <a href="one">one</a><br>
+                              <a href="two">two</a> 
+                              </body>
+                              </html>"""
+                 ...
+
+If you publish an instance of the 'Example' class with the URL
+'http://zope/example', then the relative link to method 'one' will be
+'http://zope/one', instead of the correct link,
+'http://zope/example/one'.
+
+
+Zope solves this problem for you by inserting a 'base' tag inside the
+'head' tag in the HTML output of 'index_html' method when it is
+accessed as the default method. You will probably never notice this,
+but if you see a mysterious 'base' tag in your HTML output, know you
+know where it came from. You can avoid this behavior by manually
+setting your own base with a 'base' tag in your 'index_html' method
+output.
+
+
+Response Headers
+----------------
+
+The publisher and the web server take care of setting response
+headers such as 'Content-Length' and 'Content-Type'. Later in
+the chapter you'll find out how to control these headers.
+Later you'll also find out how exceptions are used to set the
+HTTP response code.
+
+Pre-Traversal Hook
+------------------
+
+The pre-traversal hook allows your objects to take special action
+before they are traversed. This is useful for doing things like
+changing the request. Applications of this include special
+authentication controls, and virtual hosting support.
+
+If your object has a method named '__before_publishing_traverse__',
+the publisher will call it with the current object and the request,
+before traversing your object. Most often your method will change the
+request. The publisher ignores anything you return from the
+pre-traversal hook method.
+
+The 'ZPublisher.BeforeTraverse' module contains some functions that
+help you register pre-traversal callbacks. This allows you to perform
+fairly complex callbacks to multiple objects when a given object is
+about to be traversed.
+
+
+Traversal and Acquisition
+-------------------------
+
+Acquisition affects traversal in several ways. See Chapter 5,
+"Acquisition" for more information on acquisition. The most obvious
+way in which acquisition affects traversal is in locating the next
+object in a path. As we discussed earlier, the next object during
+traversal is often found using 'getattr'. Since acquisition affects
+'getattr', it will affect traversal. The upshot is that when you are
+traversing objects that support implicit acquisition, you can use
+traversal to walk over acquired objects. Consider the object
+hierarchy rooted in 'fruit'::
+
+        from Acquisition import Implicit
+
+        class Node(Implicit):
+            ...
+
+        fruit=Node()
+        fruit.apple=Node()
+        fruit.orange=Node()
+        fruit.apple.strawberry=Node()
+        fruit.orange.banana=Node()
+
+When publishing these objects, acquisition can come into play. For
+example, consider the URL */fruit/apple/orange*. The publisher would
+traverse from 'fruit', to 'apple', and then using acquisition, it
+would traverse to 'orange'.
+
+Mixing acquisition and traversal can get complex. Consider the URL
+*/fruit/apple/orange/strawberry/banana*. This URL is functional but
+confusing. Here's an even more perverse but legal URL
+*/fruit/apple/orange/orange/apple/apple/banana*.
+
+
+In general you should limit yourself to constructing URLs which use
+acquisition to acquire along containment, rather than context
+lines. It's reasonable to publish an object or method that you
+acquire from your container, but it's probably a bad idea to publish
+an object or method that your acquire from outside your
+container. For example::
+
+        from Acquisition import Implicit
+
+        class Basket(Implicit):
+            ...
+            def numberOfItems(self):
+                "Returns the number of contained items"
+                ...
+
+        class Vegetable(Implicit):
+            ...
+            def texture(self):
+                "Returns the texture of the vegetable."
+
+        class Fruit(Implicit):
+            ...
+            def color(self):
+                "Returns the color of the fruit."
+
+         basket=Basket()
+         basket.apple=Fruit()
+         basket.carrot=Vegetable()
+
+The URL */basket/apple/numberOfItems* uses acquisition along
+containment lines to publish the 'numberOfItems' method (assuming
+that 'apple' doesn't have a 'numberOfItems' attribute). However, the
+URL */basket/carrot/apple/texture* uses acquisition to locate the
+'texture' method from the 'apple' object's context, rather than from
+its container. While this distinction may be obscure, the guiding
+idea is to keep URLs as simple as possible. By keeping acquisition
+simple and along containment lines your application increases in
+clarity, and decreases in fragility.
+
+
+A second usage of acquisition in traversal concerns the request. The
+publisher tries to make the request available to the published object
+via acquisition. It does this by wrapping the first object in an
+acquisition wrapper that allows it to acquire the request with the
+name 'REQUEST'. This means that you can normally acquire the request
+in the published object like so::
+
+        request=self.REQUEST # for implicit acquirers
+
+or like so::
+
+        request=self.aq_acquire('REQUEST') # for explicit acquirers
+
+Of course, this will not work if your objects do not support
+acquisition, or if any traversed objects have an attribute named
+'REQUEST'.
+
+Finally, acquisition has a totally different role in object
+publishing related to security which we'll examine next.
+
+Traversal and Security
+----------------------
+
+As the publisher moves from object to object during traversal it
+makes security checks. The current user must be authorized to access
+each object along the traversal path. The publisher controls access
+in a number of ways. For more information about Zope security, see
+Chapter 6, "Security".
+
+Basic Publisher Security
+------------------------
+
+The publisher imposes a few basic restrictions on traversable
+objects. These restrictions are the same of those for publishable
+objects. As previously stated, publishable objects must have doc
+strings and must not have names beginning with underscore.
+
+The following details are not important if you are using the Zope
+framework. However, if your are publishing your own modules, the rest
+of this section will be helpful.
+
+The publisher checks authorization by examining the '__roles__'
+attribute of each object as it performs traversal. If present, the
+'__roles__' attribute should be 'None' or a list of role names. If it
+is None, the object is considered public. Otherwise the access to the
+object requires validation.
+
+Some objects such as functions and methods do not support creating
+attributes (at least they didn't before Python 2). Consequently, if
+the object has no '__roles__' attribute, the publisher will look for
+an attribute on the object's parent with the name of the object
+followed by '__roles__'. For example, a function named 'getInfo'
+would store its roles in its parent's 'getInfo__roles__' attribute.
+
+If an object has a '__roles__' attribute that is not empty and not
+'None', the publisher tries to find a user database to authenticate
+the user. It searches for user databases by looking for an
+'__allow_groups__' attribute, first in the published object, then in
+the previously traversed object, and so on until a user database is
+found.
+
+When a user database is found, the publisher attempts to validate the
+user against the user database. If validation fails, then the
+publisher will continue searching for user databases until the user
+can be validated or until no more user databases can be found.
+
+The user database may be an object that provides a validate
+method::
+
+  validate(request, http_authorization, roles)
+
+where 'request' is a mapping object that contains request
+information, 'http_authorization' is the value of the HTTP
+'Authorization' header or 'None' if no authorization header was
+provided, and 'roles' is a list of user role names.
+
+The validate method returns a user object if succeeds, and 'None' if
+it cannot validate the user. See Chapter 6 for more information on
+user objects. Normally, if the validate method returns 'None', the
+publisher will try to use other user databases, however, a user
+database can prevent this by raising an exception.
+
+
+If validation fails, Zope will return an HTTP header that causes your
+browser to display a user name and password dialog. You can control
+the realm name used for basic authentication by providing a module
+variable named '__bobo_realm__'. Most web browsers display the realm
+name in the user name and password dialog box.
+
+If validation succeeds the publisher assigns the user object to the
+request variable, 'AUTHENTICATED_USER'. The publisher places no
+restriction on user objects.
+
+
+Zope Security
+
+When using Zope rather than publishing your own modules, the
+publisher uses acquisition to locate user folders and perform
+security checks. The upshot of this is that your published objects
+must inherit from 'Acquisition.Implicit' or
+'Acquisition.Explicit'. See Chapter 5, "Acquisition", for more
+information about these classes. Also when traversing each object
+must be returned in an acquisition context. This is done
+automatically when traversing via 'getattr', but you must wrap
+traversed objects manually when using '__getitem__' and
+'__bobo_traverse__'. For example::
+
+          class Example(Acquisition.Explicit):
+              ...
+
+              def __bobo_traverse__(self, name, request):
+                  ...
+                  next_object=self._get_next_object(name)
+                  return  next_object.__of__(self)      
+
+
+Finally, traversal security can be circumvented with the
+'__allow_access_to_unprotected_subobjects__' attribute as described
+in Chapter 6, "Security".
+
+
+Environment Variables
+=====================
+
+You can control some facets of the publisher's operation by setting
+environment variables.
+
+- 'Z_DEBUG_MODE' -- Sets debug mode. In debug mode tracebacks are not
+  hidden in error pages. Also debug mode causes 'DTMLFile' objects,
+  External Methods and help topics to reload their contents from disk
+  when changed. You can also set debug mode with the '-D' switch when
+  starting Zope.
+
+- 'Z_REALM' -- Sets the basic authorization realm. This controls the
+  realm name as it appears in the web browser's username and password
+  dialog. You can also set the realm with the '__bobo_realm__' module
+  variable, as mentioned previously.
+
+- 'PROFILE_PUBLISHER' -- Turns on profiling and sets the name of the
+  profile file. See the Python documentation for more information
+  about the Python profiler.
+
+
+Many more options can be set using switches on the startup
+script. See the *Zope Administrator's Guide* for more information.
+
+Testing
+-------
+
+ZPublisher comes with built-in support for testing and working with
+the Python debugger.  This topic is covered in more detail in Chapter
+7, "Testing and Debugging".
+
+Publishable Module
+------------------
+
+If you are using the Zope framework, this section will be irrelevant
+to you. However, if you are publishing your own modules with
+'ZPublisher' read on.
+
+The publisher begins the traversal process by locating an object in
+the module's global namespace that corresponds to the first element
+of the path. Alternately the first object can be located by one of
+two hooks.
+
+If the module defines a 'web_objects' or 'bobo_application' object,
+the first object is searched for in those objects. The search happens
+according to the normal rules of traversal, using
+'__bobo_traverse__', 'getattr', and '__getitem__'.
+
+The module can receive callbacks before and after traversal. If the
+module defines a '__bobo_before__' object, it will be called with no
+arguments before traversal. Its return value is ignored. Likewise, if
+the module defines a '__bobo_after__' object, it will be called after
+traversal with no arguments. These callbacks can be used for things
+like acquiring and releasing locks.
+
+Calling the Published Object
+----------------------------
+
+Now that we've covered how the publisher located the published object
+and what it does with the results of calling it, let's take a closer
+look at how the published object is called.
+
+The publisher marshals arguments from the request and automatically
+makes them available to the published object. This allows you to
+accept parameters from web forms without having to parse the
+forms. Your objects usually don't have to do anything special to be
+called from the web. Consider this function::
+
+      def greet(name):
+          "greet someone"
+          return "Hello, %s" % name
+
+You can provide the 'name' argument to this function by calling it
+with a URL like *greet?name=World*. You can also call it with a HTTP
+'POST' request which includes 'name' as a form variable.
+
+In the next sections we'll take a closer look at how the publisher
+marshals arguments.
+
+Marshalling Arguments from the Request
+--------------------------------------
+
+The publisher marshals form data from GET and POST requests. Simple
+form fields are made available as Python strings. Multiple fields
+such as form check boxes and multiple selection lists become
+sequences of strings. File upload fields are represented with
+'FileUpload' objects. File upload objects behave like normal Python
+file objects and additionally have a 'filename' attribute which is
+the name of the file and a 'headers' attribute which is a dictionary
+of file upload headers.
+
+The publisher also marshals arguments from CGI environment variables
+and cookies. When locating arguments, the publisher first looks in
+CGI environment variables, then other request variables, then form
+data, and finally cookies. Once a variable is found, no further
+searching is done. So for example, if your published object expects
+to be called with a form variable named 'SERVER_URL', it will fail,
+since this argument will be marshaled from the CGI environment first,
+before the form data.
+
+The publisher provides a number of additional special variables such
+as 'URL0' which are derived from the request. These are covered in
+the 'HTTPRequest' API documentation.
+
+Argument Conversion
+-------------------
+
+The publisher supports argument conversion. For example consider this
+function::
+
+        def onethird(number):
+            "returns the number divided by three"
+            return number / 3.0
+
+This function cannot be called from the web because by default the
+publisher marshals arguments into strings, not numbers. This is why
+the publisher provides a number of converters. To signal an argument
+conversion you name your form variables with a colon followed by a
+type conversion code. For example, to call the above function with 66
+as the argument you can use this URL *onethird?number:int=66* The
+publisher supports many converters:
+
+- boolean -- Converts a variable to true or false. Variables that are
+  0, None, an empty string, or an empty sequence are false, all
+  others are true.
+
+- int -- Converts a variable to a Python integer.
+
+- long -- Converts a variable to a Python long integer.
+
+- float -- Converts a variable to a Python floating point number.
+
+- string -- Converts a variable to a Python string.
+
+- ustring -- Converts a variable to a Python unicode string.
+
+- required -- Raises an exception if the variable is not present or
+  is an empty string.
+
+- ignore_empty -- Excludes a variable from the request if the
+  variable is an empty string.
+
+- date -- Converts a string to a *DateTime* object. The formats
+  accepted are fairly flexible, for example '10/16/2000', '12:01:13
+  pm'.
+
+- list -- Converts a variable to a Python list of values, even if
+  there is only one value.
+
+- tuple -- Converts a variable to a Python tuple of values, even if
+  there is only one value.
+
+- lines -- Converts a string to a Python list of values by splitting
+  the string on line breaks.
+
+- tokens -- Converts a string to a Python list of values by splitting
+  the string on spaces.
+
+- text -- Converts a variable to a string with normalized line
+  breaks.  Different browsers on various platforms encode line
+  endings differently, so this converter makes sure the line endings
+  are consistent, regardless of how they were encoded by the browser.
+
+- ulines, utokens, utext -- like lines, tokens, text, but using
+  unicode strings instead of plain strings.
+
+If the publisher cannot coerce a request variable into the type
+required by the type converter it will raise an error. This is useful
+for simple applications, but restricts your ability to tailor error
+messages. If you wish to provide your own error messages, you should
+convert arguments manually in your published objects rather than
+relying on the publisher for coercion. Another possibility is to use
+JavaScript to validate input on the client-side before it is
+submitted to the server.
+
+You can combine type converters to a limited extent. For example you
+could create a list of integers like so::
+
+        <input type="checkbox" name="numbers:list:int" value="1">
+        <input type="checkbox" name="numbers:list:int" value="2">
+        <input type="checkbox" name="numbers:list:int" value="3">
+
+In addition to these type converters, the publisher also supports
+method and record arguments.
+
+Character Encodings for Arguments
+---------------------------------
+
+The publisher needs to know what character encoding was used by the
+browser to encode form fields into the request. That depends on
+whether the form was submitted using GET or POST (which the publisher
+can work out for itself) and on the character encoding used by the
+page which contained the form (for which the publisher needs your
+help).
+
+In some cases you need to add a specification of the character
+encoding to each fields type converter. The full details of how this
+works are explained below, however most users do not need to deal
+with the full details:
+
+1. If your pages all use the UTF-8 character encoding (or at least
+   all the pages that contain forms) the browsers will always use
+   UTF-8 for arguments. You need to add ':utf8' into all argument
+   type converts. For example:
+
+   <input type="text" name="name:utf8:ustring">
+   <input type="checkbox" name="numbers:list:int:utf8" value="1">
+   <input type="checkbox" name="numbers:list:int:utf8" value="1">
+
+     % Anonymous User - Apr. 6, 2004 5:56 pm:
+      121
+
+2. If your pages all use a character encoding which has ASCII as a
+   subset (such as Latin-1, UTF-8, etc) then you do not need to
+   specify any chatacter encoding for boolean, int, long, float, and
+   date types.  You can also omit the character encoding type
+   converter from string, tokens, lines, and text types if you only
+   need to handle ASCII characters in that form field.
+
+Character Encodings for Arguments; The Full Story
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you are not in one of those two easy categories, you first need to
+determine which character encoding will be used by the browser to
+encode the arguments in submitted forms.
+
+1. Forms submitted using GET, or using POST with 
+   "application/x-www-form-urlencoded" (the default) 
+
+   1. Page uses an encoding of unicode: Forms are submitted using
+      UTF8, as required by RFC 2718 2.2.5
+
+   2. Page uses another regional 8 bit encoding: Forms are often
+      submitted using the same encoding as the page. If you choose to
+      use such an encoding then you should also verify how browsers
+      behave.
+
+2. Forms submitted using "multipart/form-data":
+
+   According to HTML 4.01 (section 17.13.4) browsers should state
+   which character encoding they are using for each field in a
+   Content-Type header, however this is poorly supported. The current
+   crop of browsers appear to use the same encoding as the page
+   containing the form.
+
+   Every field needs that character encoding name appended to is
+   converter.  The tag parser insists that tags must only use
+   alphanumberic characters or an underscore, so you might need to
+   use a short form of the encoding name from the Python 'encodings'
+   library package (such as utf8 rather than UTF-8).
+
+
+Method Arguments
+----------------
+
+Sometimes you may wish to control which object is published based on
+form data. For example, you might want to have a form with a select
+list that calls different methods depending on the item
+chosen. Similarly, you might want to have multiple submit buttons
+which invoke a different method for each button.
+
+The publisher provides a way to select methods using form variables
+through use of the *method* argument type. The method type allows the
+request 'PATH_INFO' to be augmented using information from a form
+item name or value.
+
+If the name of a form field is ':method', then the value of the field
+is added to 'PATH_INFO'. For example, if the original 'PATH_INFO' is
+'foo/bar' and the value of a ':method' field is 'x/y', then
+'PATH_INFO' is transformed to 'foo/bar/x/y'. This is useful when
+presenting a select list. Method names can be placed in the select
+option values.
+
+If the name of a form field ends in ':method' then the part of the
+name before ':method' is added to 'PATH_INFO'. For example, if the
+original 'PATH_INFO' is 'foo/bar' and there is a 'x/y:method' field,
+then 'PATH_INFO' is transformed to 'foo/bar/x/y'. In this case, the
+form value is ignored. This is useful for mapping submit buttons to
+methods, since submit button values are displayed and should,
+therefore, not contain method names.
+
+Only one method field should be provided. If more than one method
+field is included in the request, the behavior is undefined.
+
+Record Arguments 
+----------------
+
+Sometimes you may wish to consolidate form data into a structure
+rather than pass arguments individually. Record arguments allow you
+to do this.
+
+The 'record' type converter allows you to combine multiple
+form variables into a single input variable. For example::
+
+  <input name="date.year:record:int">
+  <input name="date.month:record:int">
+  <input name="date.day:record:int">
+
+This form will result in a single variable, 'date', with
+attributes 'year', 'month', and 'day'.
+
+You can skip empty record elements with the 'ignore_empty'
+converter. For example::
+
+  <input type="text" name="person.email:record:ignore_empty">
+
+When the email form field is left blank the publisher skips over the
+variable rather than returning a null string as its value. When the
+record 'person' is returned it will not have an 'email' attribute if
+the user did not enter one.
+
+You can also provide default values for record elements with the
+'default' converter. For example::
+
+  <input type="hidden"
+         name="pizza.toppings:record:list:default" 
+         value="All">
+  <select multiple name="pizza.toppings:record:list:ignore_empty">
+  <option>Cheese</option>
+  <option>Onions</option>
+  <option>Anchovies</option>
+  <option>Olives</option>
+  <option>Garlic<option>
+  </select>
+
+The 'default' type allows a specified value to be inserted when the
+form field is left blank. In the above example, if the user does not
+select values from the list of toppings, the default value will be
+used. The record 'pizza' will have the attribute 'toppings' and its
+value will be the list containing the word "All" (if the field is
+empty) or a list containing the selected toppings.
+
+You can even marshal large amounts of form data into multiple records
+with the 'records' type converter. Here's an example::
+
+  <h2>Member One</h2>
+  Name:
+  <input type="text" name="members.name:records"><BR>
+  Email:
+  <input type="text" name="members.email:records"><BR>
+  Age:
+  <input type="text" name="members.age:int:records"><BR>
+
+  <H2>Member Two</H2>
+  Name:
+  <input type="text" name="members.name:records"><BR>
+  Email:
+  <input type="text" name="members.email:records"><BR>
+  Age:
+  <input type="text" name="members.age:int:records"><BR>
+
+This form data will be marshaled into a list of records named
+'members'. Each record will have a 'name', 'email', and 'age'
+attribute.
+
+Record marshalling provides you with the ability to create complex
+forms. However, it is a good idea to keep your web interfaces as
+simple as possible.
+
+Exceptions
+----------
+
+Unhandled exceptions are caught by the object publisher and are
+translated automatically to nicely formatted HTTP output.
+
+When an exception is raised, the exception type is mapped to an HTTP
+code by matching the value of the exception type with a list of
+standard HTTP status names. Any exception types that do not match
+standard HTTP status names are mapped to "Internal Error" (500). The
+standard HTTP status names are: "OK", "Created", "Accepted", "No
+Content", "Multiple Choices", "Redirect", "Moved Permanently", "Moved
+Temporarily", "Not Modified", "Bad Request", "Unauthorized",
+"Forbidden", "Not Found", "Internal Error", "Not Implemented", "Bad
+Gateway", and "Service Unavailable". Variations on these names with
+different cases and without spaces are also valid.
+
+An attempt is made to use the exception value as the body of the
+returned response. The object publisher will examine the exception
+value. If the value is a string that contains some white space, then
+it will be used as the body of the return error message. If it
+appears to be HTML, the error content type will be set to
+'text/html', otherwise, it will be set to 'text/plain'. If the
+exception value is not a string containing white space, then the
+object publisher will generate its own error message.
+
+There are two exceptions to the above rule:
+
+1. If the exception type is: "Redirect", "Multiple Choices" "Moved
+   Permanently", "Moved Temporarily", or "Not Modified", and the
+   exception value is an absolute URI, then no body will be provided
+   and a 'Location' header will be included in the output with the
+   given URI.
+
+2. If the exception type is "No Content", then no body will be
+   returned.
+
+When a body is returned, traceback information will be included in a
+comment in the output. As mentioned earlier, the environment variable
+'Z_DEBUG_MODE' can be used to control how tracebacks are included. If
+this variable is set then tracebacks are included in 'PRE' tags,
+rather than in comments. This is very handy during debugging.
+
+Exceptions and Transactions
+---------------------------
+
+When Zope receives a request it begins a transaction. Then it begins
+the process of traversal. Zope automatically commits the transaction
+after the published object is found and called. So normally each web
+request constitutes one transaction which Zope takes care of for
+you. See Chapter 4. for more information on transactions.
+
+If an unhandled exception is raised during the publishing process,
+Zope aborts the transaction. As detailed in Chapter
+4. Zope handles 'ConflictErrors' by re-trying the request up to
+three times.  This is done with the 'zpublisher_exception_hook'.
+
+In addition, the error hook is used to return an error message to the
+user. In Zope the error hook creates error messages by calling the
+'raise_standardErrorMessage' method. This method is implemented by
+'SimpleItem.Item'. It acquires the 'standard_error_message' DTML
+object, and calls it with information about the exception.
+
+You will almost never need to override the
+'raise_standardErrorMessage' method in your own classes, since it is
+only needed to handle errors that are raised by other components. For
+most errors, you can simply catch the exceptions normally in your
+code and log error messages as needed. If you need to, you should be
+able to customize application error reporting by overriding the
+'standard_error_message' DTML object in your application.
+
+Manual Access to Request and Response
+-------------------------------------
+
+You do not need to access the request and response directly most of
+the time. In fact, it is a major design goal of the publisher that
+most of the time your objects need not even be aware that they are
+being published on the web. However, you have the ability to exert
+more precise control over reading the request and returning the
+response.
+
+Normally published objects access the request and response by listing
+them in the signature of the published method. If this is not
+possible you can usually use acquisition to get a reference to the
+request. Once you have the request, you can always get the response
+from the request like so::
+
+  response=REQUEST.RESPONSE
+
+The APIs of the request and response are covered in the API
+documentation. Here we'll look at a few common uses of the request
+and response.
+
+One reason to access the request is to get more precise information
+about form data. As we mentioned earlier, argument marshalling comes
+from a number of places including cookies, form data, and the CGI
+environment. For example, you can use the request to differentiate
+between form and cookie data::
+
+  cookies = REQUEST.cookies # a dictionary of cookie data
+  form = REQUEST.form # a dictionary of form data
+
+One common use of the response object is to set response headers.
+Normally the publisher in concert with the web server will take care
+of response headers for you. However, sometimes you may wish manually
+control headers::
+
+  RESPONSE.setHeader('Pragma', 'No-Cache')
+
+Another reason to access the response is to stream response data. You
+can do this with the 'write' method::
+
+  while 1:
+      data=getMoreData() #this call may block for a while
+      if not data:
+          break
+      RESPONSE.write(data)
+
+Here's a final example that shows how to detect if your method is
+being called from the web. Consider this function::
+
+  def feedParrot(parrot_id, REQUEST=None):
+      ...
+
+      if REQUEST is not None:
+          return "<html><p>Parrot %s fed</p></html>" % parrot_id
+
+The 'feedParrot' function can be called from Python, and also from
+the web. By including 'REQUEST=None' in the signature you can
+differentiate between being called from Python and being called form
+the web. When the function is called from Python nothing is returned,
+but when it is called from the web the function returns an HTML
+confirmation message.
+
+Other Network Protocols
+=======================
+
+FTP
+---
+
+Zope comes with an FTP server which allows users to treat the Zope
+object hierarchy like a file server. As covered in Chapter 3, Zope
+comes with base classes ('SimpleItem' and 'ObjectManager') which
+provide simple FTP support for all Zope objects. The FTP API is
+covered in the API reference.
+
+To support FTP in your objects you'll need to find a way to represent
+your object's state as a file. This is not possible or reasonable for
+all types of objects. You should also consider what users will do
+with your objects once they access them via FTP.  You should find out
+which tools users are likely to edit your object files.  For example,
+XML may provide a good way to represent your object's state, but it
+may not be easily editable by your users.  Here's an example class
+that represents itself as a file using RFC 822 format::
+
+  from rfc822 import Message
+  from cStringIO import StringIO
+
+  class Person(...):
+
+      def __init__(self, name, email, age):
+          self.name=name
+          self.email=email
+          self.age=age
+
+      def writeState(self):
+          "Returns object state as a string"
+          return "Name: %s\nEmail: %s\nAge: %s" % (self.name,
+                                                   self.email, 
+                                                   self.age)
+      def readState(self, data):
+          "Sets object state given a string"
+          m=Message(StringIO(data))
+          self.name=m['name']
+          self.email=m['email']
+          self.age=int(m['age'])
+
+The 'writeState' and 'readState' methods serialize and unserialize
+the 'name', 'age', and 'email' attributes to and from a string. There
+are more efficient ways besides RFC 822 to store instance attributes
+in a file, however RFC 822 is a simple format for users to edit with
+text editors.
+
+To support FTP all you need to do at this point is implement the
+'manage_FTPget' and 'PUT' methods. For example::
+
+  def manage_FTPget(self):
+      "Returns state for FTP"
+      return self.writeState()
+
+  def PUT(self, REQUEST):
+      "Sets state from FTP"
+       self.readState(REQUEST['BODY'])
+
+You may also choose to implement a 'get_size' method which returns
+the size of the string returned by 'manage_FTPget'. This is only
+necessary if calling 'manage_FTPget' is expensive, and there is a
+more efficient way to get the size of the file. In the case of this
+example, there is no reason to implement a 'get_size' method.
+
+One side effect of implementing 'PUT' is that your object now
+supports HTTP PUT publishing. See the next section on WebDAV for more
+information on HTTP PUT.
+
+That's all there is to making your object work with FTP. As you'll
+see next WebDAV support is similar.
+
+WebDAV
+------
+
+WebDAV is a protocol for collaboratively edit and manage files on
+remote servers. It provides much the same functionality as FTP, but
+it works over HTTP.
+
+It is not difficult to implement WebDAV support for your
+objects. Like FTP, the most difficult part is to figure out how to
+represent your objects as files.
+
+Your class must inherit from 'webdav.Resource' to get basic DAV
+support. However, since 'SimpleItem' inherits from 'Resource', your
+class probably already inherits from 'Resource'. For container
+classes you must inherit from 'webdav.Collection'. However, since
+'ObjectManager' inherits from 'Collection' you are already set so
+long as you inherit from 'ObjectManager'.
+
+In addition to inheriting from basic DAV classes, your classes must
+implement 'PUT' and 'manage_FTPget'. These two methods are also
+required for FTP support. So by implementing WebDAV support, you also
+implement FTP support.
+
+The permissions that you assign to these two methods will control the
+ability to read and write to your class through WebDAV, but the
+ability to see your objects is controlled through the "WebDAV access"
+permission.
+
+Supporting Write Locking
+------------------------
+
+Write locking is a feature of WebDAV that allows users to put lock on
+objects they are working on. Support write locking s easy. To
+implement write locking you must assert that your lass implements the
+'WriteLockInterface'. For example::
+
+  from webdav.WriteLockInterface import WriteLockInterface
+
+  class MyContentClass(OFS.SimpleItem.Item, Persistent):
+      __implements__ = (WriteLockInterface,)
+
+It's sufficient to inherit from 'SimpleItem.Item', since it inherits
+from 'webdav.Resource', which provides write locking long with other
+DAV support.
+
+In addition, your 'PUT' method should begin with calls to dav__init'
+and 'dav_simpleifhandler'. For example::
+
+ def PUT(self, REQUEST, RESPONSE):
+     """
+     Implement WebDAV/HTTP PUT/FTP put method for this object.
+     """
+     self.dav__init(REQUEST, RESPONSE)
+     self.dav__simpleifhandler(REQUEST, RESPONSE)
+     ...
+
+Finally your class's edit methods should check to determine whether
+your object is locked using the 'ws_isLocked' method. If someone
+attempts to change your object when it is locked you should raise the
+'ResourceLockedError'. For example::
+
+  from webdav import ResourceLockedError
+
+  class MyContentClass(...):
+      ...
+
+      def edit(self, ...):
+          if self.ws_isLocked():
+              raise ResourceLockedError
+          ...
+
+WebDAV support is not difficult to implement, and as more WebDAV
+editors become available, it will become more valuable. If you choose
+to add FTP support to your class you should probably go ahead and
+support WebDAV too since it is so easy once you've added FTP support.
+
+XML-RPC
+-------
+
+`XML-RPC <http://www.xmlrpc.com>`_ is a light-weight Remote Procedure
+Call protocol that uses XML for encoding and HTTP for
+transport. Fredrick Lund maintains a Python <XML-RPC module
+<http://www.pythonware.com/products/xmlrpc>`_ .
+
+All objects in Zope support XML-RPC publishing. Generally you will
+select a published object as the end-point and select one of its
+methods as the method. For example you can call the 'getId' method on
+a Zope folder at 'http://example.com/myfolder' like so::
+
+  import xmlrpclib
+  folder = xmlrpclib.Server('http://example.com/myfolder')
+  ids = folder.getId()
+
+You can also do traversal via a dotted method name. For example::
+
+  import xmlrpclib
+
+  # traversal via dotted method name
+  app = xmlrpclib.Server('http://example.com/app')
+  id1 = app.folderA.folderB.getId()
+
+  # walking directly up to the published object
+  folderB = xmlrpclib.Server('http://example.com/app/folderA/folderB')
+  id2 = folderB.getId()
+
+  print id1 == id2
+
+This example shows different routes to the same object publishing
+call.
+
+XML-RPC supports marshalling of basic Python types for both
+publishing requests and responses. The upshot of this arrangement is
+that when you are designing methods for use via XML-RPC you should
+limit your arguments and return values to simple values such as
+Python strings, lists, numbers and dictionaries. You should not
+accept or return Zope objects from methods that will be called via
+XML-RPC.
+
+
+XML-RPC does not support keyword arguments. This is a problem if your
+method expect keyword arguments.  This problem is noticeable when
+calling DTMLMethods and DTMLDocuments with XML-RPC.  Normally a DTML
+object should be called with the request as the first argument, and
+additional variables as keyword arguments.  You can get around this
+problem by passing a dictionary as the first argument. This will
+allow your DTML methods and documents to reference your variables
+with the 'var' tag.  However, you cannot do the following::
+
+  <dtml-var expr="REQUEST['argument']">
+
+Although the following will work::
+
+  <dtml-var expr="_['argument']">
+
+This is because in this case arguments *are* in the DTML namespace,
+but they are not coming from the web request.
+
+In general it is not a good idea to call DTML from XML-RPC since DTML
+usually expects to be called from normal HTTP requests.
+
+One thing to be aware of is that Zope returns 'false' for published
+objects which return None since XML-RPC has no concept of null.
+
+Another issue you may run into is that 'xmlrpclib' does not yet
+support HTTP basic authentication. This makes it difficult to call
+protected web resources. One solution is to patch
+'xmlrpclib'. Another solution is to accept authentication credentials
+in the signature of your published method.
+
+Summary
+=======
+
+Object publishing is a simple and powerful way to bring objects to
+the web. Two of Zope's most appealing qualities is how it maps
+objects to URLs, and you don't need to concern yourself with web
+plumbing. If you wish, there are quite a few details that you can use
+to customize how your objects are located and published.
+

Copied: zope2docs/branches/baijum-reorganize/zdgbook/Outline.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/Outline.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/Outline.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/Outline.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,159 @@
+#######
+Outline
+#######
+
+Covers audience, topic, and scope.  Gives brief description of the
+developers guide and what goals the guide tries to acomplish.  Gives
+simple chapter by chapter overview of entire guide.
+
+
+Interfaces
+==========
+
+Zope is moving toward a more "self-documenting" model, where Zope
+component describe themselves with interfaces.  Many of the prose
+descriptions and examples in this guide will be working with these
+kinds of components.  This chapter gives a brief overview of Zope
+interfaces, how they describe Zope components, and how developers can
+create their own interfaces.
+
+This section is meant to enable the reader to discover the Zope "API"
+for themselves.  One of the goals of this guide is *not* to be an
+exhaustive descrption of the Zope API, that can be found in the
+online help system and from Zope objects through their interfaces.
+
+The majority of the content of this chapter will come from the
+`Interface documentation
+<http://www.zope.org/Wikis/Interfaces/InterfaceUserDocumentation>`_
+
+1. What are interfaces, why are they useful?
+
+2. Reading interfaces
+
+3. Using and testing interfaces
+
+4. Defining interfaces
+
+
+Publishing
+==========
+
+One key facility that Zope provides for a component developer is
+access to a component through various network protocols, like HTTP.
+While a component can be designed to work exclusivly with other
+components through Python only interfaces, most components are
+designed to be used and managed through a network interface, most
+commonly HTTP.
+
+Zope provides network access to components by "publishing" them
+through various network interfaces like HTTP, FTP, WebDAV and
+XML-RPC.  This chapter describes how a component developer can
+publish their components "through the web" and other network
+protocols.
+
+1. Object publishing overview
+
+2. Traversal
+
+3. Network Protocols
+
+4. Publishable Interfaces
+
+5. Object marshalling
+
+6. Creating user interfaces
+
+   - with DTMLFile
+
+   - with presentation templates
+
+
+Products
+========
+
+Zope defines a system that allows component developers to distribute
+their components to other Zope users.  Components can be placed into
+a package called a "Product".  Products can be created either through
+the web, or in Python.  Through the web products are covered in *The
+Zope Book*, and this chapter describes the more advanced Python
+product interfaces that developers can use to distribute their
+Python-based components.
+
+The majority of the content of this chapter will come from
+Amos/Shane's `Product Tutorial
+<http://www.zope.org/Members/hathawsh/PythonProductTutorial>`_
+
+1. Introduction
+
+2. Development Process
+
+3. Product Architecture
+
+4. Building Product Classes
+
+5. Building Management Interfaces
+
+6. Packaging Products
+
+7. Evolving Products
+
+
+Persistence
+===========
+
+Most Zope components live in the Zope Object DataBase (ZODB).
+Components that are stored in ZODB are called *persistent*.  Creating
+persistent components is, for the most part, a trivial exercise, but
+ZODB does impose a few rules that persistent components must obey in
+oder to work properly.  This chapter describes the persistent model
+and the interfaces that persistent objects can use to live inside the
+ZODB.
+
+1. Persistence Architecture
+
+2. Using Persistent components
+
+3. Creating Persistent Objects
+
+4. Transactions
+
+
+Security
+========
+
+Zope has a very fine-grained, uniquely powerful security model.  This
+model allows Zope developers to create components that work safely in
+an environment used by many different users, all with varying levels
+of security privledge.
+
+This section describes Zope's security model and how component
+developers can work with it and manipulate it to define security
+policies specific to their needs or the needs of their components.
+
+The majority of the content of this chapter will come from Chris'
+first cut at `Security documentation
+<http://www.zope.org/Members/mcdonc/PDG/6-1-Security.stx>`_
+
+1. Security architecture
+
+2. Using protected components
+
+3. Implementing Security in your Component
+
+4. Security Policies
+
+
+Debugging and Testing
+=====================
+
+Covers debugging Zope and unit testing.
+
+- pdb debugging
+
+- Control Panel debug view
+
+- -D z2.py switch
+
+- unit testing
+
+  - zope fixtures for unit testing

Copied: zope2docs/branches/baijum-reorganize/zdgbook/Products.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/Products.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/Products.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/Products.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,1322 @@
+#############
+Zope Products
+#############
+
+Introduction
+============
+
+Zope *products* extend Zope with new functionality.  Products most
+often provide new addable objects.  In this chapter, we are going to
+look at building products on the file system.  Filesystem products
+require more overhead to build, but offer more power and flexibility,
+and they can be developed with familiar tools such as text editors
+and version controlling systems.
+
+Soon we will make the examples referenced in this chapter available
+for download as an example product.  Until that time, you will see
+references to files in this chapter that are not available yet.  This
+will be made available soon.
+
+Development Process
+===================
+
+This chapter begins with a discussion of how you will develop
+products.  We'll focus on common engineering tasks that you'll
+encounter as you develop products.
+
+Consider Alternatives
+---------------------
+
+Before you jump into the development of a product you should consider
+the alternatives.  Would your problem be better solved with External
+Methods, or Python Scripts? Products excel at extending Zope with new
+addable classes of objects.  If this does not figure centrally in
+your solution, you should look elsewhere.  Products, like External
+Methods allow you to write unrestricted Python code on the
+filesystem.
+
+Starting with Interfaces
+------------------------
+
+The first step in creating a product is to create one or more
+interfaces which describe the product.  See Chapter 2 for more
+information on interfaces and how to create them.
+
+Creating interfaces before you build an implementation is a good idea
+since it helps you see your design and assess how well it fulfills
+your requirements.
+
+Consider this interface for a multiple choice poll component (see
+`Poll.py <examples/Poll.py>`_)::
+
+  from zope.interface import Interface
+
+  class IPoll(Interface):
+      """A multiple choice poll"""
+
+      def castVote(index):
+          """Votes for a choice"""
+
+      def getTotalVotes():
+          """Returns total number of votes cast"""
+
+      def getVotesFor(index):
+          """Returns number of votes cast for a given response"""
+
+      def getResponses():
+          """Returns the sequence of responses"""
+
+      def getQuestion():
+          """Returns the question"""
+
+How you name your interfaces is entirely up to you.  Here we've
+decided to use prefix "I" in the name of the interface.
+
+Implementing Interfaces
+-----------------------
+
+After you have defined an interface for your product, the next step
+is to create a prototype in Python that implements your interface.
+
+Here is a prototype of a ``PollImplemtation`` class that implements the
+interface you just examined (see `PollImplementation.py
+<examples/PollImplementation.py>`_)::
+
+  from poll import Poll
+
+  class PollImplementation:
+      """A multiple choice poll, implements the Poll interface.
+
+      The poll has a question and a sequence of responses. Votes
+      are stored in a dictionary which maps response indexes to a
+      number of votes.
+      """
+
+      implements(IPoll)
+
+      def __init__(self, question, responses):
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+
+      def castVote(self, index):
+          """Votes for a choice"""
+          self._votes[index] = self._votes[index] + 1
+
+      def getTotalVotes(self):
+          """Returns total number of votes cast"""
+          total = 0
+          for v in self._votes.values():
+              total = total + v
+          return total
+
+      def getVotesFor(self, index):
+          """Returns number of votes cast for a given response"""
+          return self._votes[index]
+
+      def getResponses(self):
+          """Returns the sequence of responses"""
+          return tuple(self._responses)
+
+      def getQuestion(self):
+          """Returns the question"""
+          return self._question
+
+You can use this class interactively and test it.  Here's an example
+of interactive testing::
+
+  >>> from PollImplementation import PollImplementation
+  >>> p = PollImplementation("What's your favorite color?",
+  ...                        ["Red", "Green", "Blue", "I forget"])
+  >>> p.getQuestion()
+  "What's your favorite color?"
+  >>> p.getResponses()
+  ('Red', 'Green', 'Blue', 'I forget')
+  >>> p.getVotesFor(0)
+  0
+  >>> p.castVote(0)
+  >>> p.getVotesFor(0)
+  1
+  >>> p.castVote(2)
+  >>> p.getTotalVotes()
+  2
+  >>> p.castVote(4)
+  Traceback (innermost last):
+  File "<stdin>", line 1, in ?
+  File "PollImplementation.py", line 23, in castVote
+  self._votes[index] = self._votes[index] + 1
+  KeyError: 4
+
+Interactive testing is one of Python's great features.  It lets you
+experiment with your code in a simple but powerful way.
+
+At this point you can do a fair amount of work, testing and refining
+your interfaces and classes which implement them.  See Chapter 9 for
+more information on testing.
+
+So far you have learned how to create Python classes that are
+documented with interfaces, and verified with testing.  Next you'll
+examine the Zope product architecture.  Then you'll learn how to fit
+your well crafted Python classes into the product framework.
+
+Building Product Classes
+------------------------
+
+To turn a component into a product you must fulfill many contracts.
+For the most part these contracts are not yet defined in terms of
+interfaces.  Instead you must subclass from base classes that
+implement the contracts.  This makes building products confusing, and
+this is an area that we are actively working on improving.
+
+Base Classes
+------------
+
+Consider an example product class definition::
+
+  from Acquisition import Implicit
+  from Globals import Persistent
+  from AccessControl.Role import RoleManager
+  from OFS.SimpleItem import Item
+
+  class PollProduct(Implicit, Persistent, RoleManager, Item):
+      """
+      Poll product class
+      """
+      ...
+
+The order of the base classes depends on which classes you want to
+take precedence over others.  Most Zope classes do not define similar
+names, so you usually don't need to worry about what order these
+classes are used in your product.  Let's take a look at each of these
+base classes.
+
+
+Acquisition.Implicit
+~~~~~~~~~~~~~~~~~~~~
+
+This is the normal acquisition base class.  See the *API Reference*
+for the full details on this class.  Many Zope services such as
+object publishing and security use acquisition, so inheriting from
+this class is required for products.  Actually, you can choose to
+inherit from ``Acquisition.Explicit`` if you prefer, however, it will
+prevent folks from dynamically binding Python Scripts and DTML
+Methods to instances of your class.  In general you should subclass
+from ``Acquisition.Implicit`` unless you have a good reason not to.
+
+  XXX: is this true?  I thought that any ExtensionClass.Base can be
+  acquired.  The Implicit and Explicit just control how the class can
+  acquire, not how it *is* acquired.
+
+Globals.Persistent
+~~~~~~~~~~~~~~~~~~
+
+This base class makes instances of your product persistent.  For more
+information on persistence and this class see Chapter 4.
+
+In order to make your poll class persistent you'll need to make one
+change.  Since ``_votes`` is a dictionary this means that it's a
+mutable non-persistent sub-object.  You'll need to let the
+persistence machinery know when you change it::
+
+  def castVote(self, index):
+      """Votes for a choice"""
+      self._votes[index] = self._votes[index] + 1
+      self._p_changed = 1
+
+The last line of this method sets the ``_p_changed`` attribute to 1.
+This tells the persistence machinery that this object has changed and
+should be marked as ``dirty``, meaning that its new state should be
+written to the database at the conclusion of the current transaction.
+A more detailed explanation is given in the Persistence chapter of
+this guide.
+
+
+OFS.SimpleItem.Item
+~~~~~~~~~~~~~~~~~~~
+
+This base class provides your product with the basics needed to work
+with the Zope management interface.  By inheriting from ``Item`` your
+product class gains a whole host of features: the ability to be cut
+and pasted, capability with management views, WebDAV support, basic
+FTP support, undo support, ownership support, and traversal controls.
+It also gives you some standard methods for management views and
+error display including ``manage_main()``.  You also get the
+``getId()``, ``title_or_id()``, ``title_and_id()`` methods and the
+``this()`` DTML utility method.  Finally this class gives your
+product basic *dtml-tree* tag support.  ``Item`` is really an
+everything-but-the-kitchen-sink kind of base class.
+
+``Item`` requires that your class and instances have some management
+interface related attributes.
+
+- ``meta_type`` -- This attribute should be a short string which is
+  the name of your product class as it appears in the product add
+  list.  For example, the poll product class could have a
+  ``meta_type`` with value as ``Poll``.
+
+- ``id`` or ``__name__`` -- All ``Item`` instances must have an
+  ``id`` string attribute which uniquely identifies the instance
+  within it's container.  As an alternative you may use ``__name__``
+  instead of ``id``.
+
+- ``title`` -- All ``Item`` instances must have a ``title`` string
+  attribute.  A title may be an empty string if your instance does
+  not have a title.
+
+In order to make your poll class work correctly as an ``Item`` you'll
+need to make a few changes.  You must add a ``meta_type`` class
+attribute, and you may wish to add an ``id`` parameter to the
+constructor::
+
+  class PollProduct(..., Item):
+
+      meta_type = 'Poll'
+      ...
+
+      def __init__(self, id, question, responses):
+          self.id = id
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+
+
+Finally, you should probably place ``Item`` last in your list of base
+classes.  The reason for this is that ``Item`` provides defaults that
+other classes such as ``ObjectManager`` and ``PropertyManager``
+override.  By placing other base classes before ``Item`` you allow
+them to override methods in ``Item``.
+
+AccessControl.Role.RoleManager
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This class provides your product with the ability to have its
+security policies controlled through the web.  See Chapter 6 for more
+information on security policies and this class.
+
+OFS.ObjectManager
+~~~~~~~~~~~~~~~~~
+
+This base class gives your product the ability to contain other
+``Item`` instances.  In other words, it makes your product class like
+a Zope folder.  This base class is optional. See the *API Reference*
+for more details.  This base class gives you facilities for adding
+Zope objects, importing and exporting Zope objects, WebDAV, and FTP.
+It also gives you the ``objectIds``, ``objectValues``, and
+``objectItems`` methods.
+
+``ObjectManager`` makes few requirements on classes that subclass it.
+You can choose to override some of its methods but there is little
+that you must do.
+
+If you wish to control which types of objects can be contained by
+instances of your product you can set the ``meta_types`` class
+attribute.  This attribute should be a tuple of meta_types.  This
+keeps other types of objects from being created in or pasted into
+instances of your product.  The ``meta_types`` attribute is mostly
+useful when you are creating specialized container products.
+
+OFS.PropertyManager
+~~~~~~~~~~~~~~~~~~~
+
+This base class provides your product with the ability to have
+user-managed instance attributes.  See the *API Reference* for more
+details.  This base class is optional.
+
+Your class may specify that it has one or more predefined properties,
+by specifying a '_properties' class attribute.  For example::
+
+  _properties=({'id':'title', 'type': 'string', 'mode': 'w'},
+               {'id':'color', 'type': 'string', 'mode': 'w'},
+              )
+
+The ``_properties`` structure is a sequence of dictionaries, where
+each dictionary represents a predefined property.  Note that if a
+predefined property is defined in the ``_properties`` structure, you
+must provide an attribute with that name in your class or instance
+that contains the default value of the predefined property.
+
+Each entry in the ``_properties`` structure must have at least an
+``id`` and a ``type`` key.  The ``id`` key contains the name of the
+property, and the ``type`` key contains a string representing the
+object's type.  The ``type`` string must be one of the values:
+``float``, ``int``, ``long``, ``string``, ``lines``, ``text``,
+``date``, ``tokens``, ``selection``, or ``multiple section``.  For
+more information on Zope properties see the *Zope Book*.
+
+For ``selection`` and ``multiple selection`` properties, you must
+include an addition item in the property dictionary,
+``select_variable`` which provides the name of a property or method
+which returns a list of strings from which the selection(s) can be
+chosen.  For example::
+
+  _properties=({'id' : 'favorite_color',
+                'type' : 'selection',
+                'select_variable' : 'getColors'
+               },
+              )
+
+Each entry in the ``_properties`` structure may optionally provide a
+``mode`` key, which specifies the mutability of the property. The
+``mode`` string, if present, must be ``w``, ``d``, or ``wd``.
+
+A ``w`` present in the mode string indicates that the value of the
+property may be changed by the user.  A ``d`` indicates that the user
+can delete the property.  An empty mode string indicates that the
+property and its value may be shown in property listings, but that it
+is read-only and may not be deleted.
+
+Entries in the ``_properties`` structure which do not have a ``mode``
+item are assumed to have the mode ``wd`` (writable and deleteable).
+
+Security Declarations
+---------------------
+
+In addition to inheriting from a number of standard base classes, you
+must declare security information in order to turn your component
+into a product.  See Chapter 6 for more information on security and
+instructions for declaring security on your components.
+
+Here's an example of how to declare security on the poll class::
+
+  from AccessControl import ClassSecurityInfo
+
+  class PollProduct(...):
+      ...
+
+      security = ClassSecurityInfo()
+
+      security.declareProtected('Use Poll', 'castVote')
+      def castVote(self, index):
+          ...
+
+      security.declareProtected('View Poll results', 'getTotalVotes')
+      def getTotalVotes(self):
+          ...
+
+      security.declareProtected('View Poll results', 'getVotesFor')
+      def getVotesFor(self, index):
+          ...
+
+      security.declarePublic('getResponses')
+      def getResponses(self):
+          ...
+
+      security.declarePublic('getQuestion')
+      def getQuestion(self):
+          ...
+
+For security declarations to be set up Zope requires that you
+initialize your product class.  Here's how to initialize your poll
+class::
+
+  from Globals import InitializeClass
+
+  class PollProduct(...):
+     ...
+
+  InitializeClass(PollProduct)
+
+Summary
+-------
+
+Congratulations, you've created a product class.  Here it is in all
+its glory (see `examples/PollProduct.py <PollProduct.py>`_)::
+
+  from Poll import Poll
+  from AccessControl import ClassSecurityInfo
+  from Globals import InitializeClass
+  from Acquisition import Implicit
+  from Globals import Persistent
+  from AccessControl.Role import RoleManager
+  from OFS.SimpleItem import Item
+
+  class PollProduct(Implicit, Persistent, RoleManager, Item):
+      """Poll product class, implements Poll interface.
+
+      The poll has a question and a sequence of responses. Votes
+      are stored in a dictionary which maps response indexes to a
+      number of votes.
+      """
+
+      implements(IPoll)
+
+      meta_type = 'Poll'
+
+      security = ClassSecurityInfo()
+
+      def __init__(self, id, question, responses):
+          self.id = id
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+
+      security.declareProtected('Use Poll', 'castVote')
+      def castVote(self, index):
+          "Votes for a choice"
+          self._votes[index] = self._votes[index] + 1
+          self._p_changed = 1
+
+      security.declareProtected('View Poll results', 'getTotalVotes')
+      def getTotalVotes(self):
+          "Returns total number of votes cast"
+          total = 0
+          for v in self._votes.values():
+              total = total + v
+          return total
+
+      security.declareProtected('View Poll results', 'getVotesFor')
+      def getVotesFor(self, index):
+          "Returns number of votes cast for a given response"
+          return self._votes[index]
+
+      security.declarePublic('getResponses')
+      def getResponses(self):
+          "Returns the sequence of responses"
+          return tuple(self._responses)
+
+      security.declarePublic('getQuestion')
+      def getQuestion(self):
+          "Returns the question"
+          return self._question
+
+  InitializeClass(Poll)
+
+Now it's time to test your product class in Zope.  To do this you
+must register your product class with Zope.
+
+Registering Products
+====================
+
+Products are Python packages that live in 'lib/python/Products'.
+Products are loaded into Zope when Zope starts up.  This process is
+called *product initialization*.  During product initialization, each
+product is given a chance to register its capabilities with Zope.
+
+Product Initialization
+----------------------
+
+When Zope starts up it imports each product and calls the product's
+'initialize' function passing it a registrar object.  The
+'initialize' function uses the registrar to tell Zope about its
+capabilities.  Here is an example '__init__.py' file::
+
+  from PollProduct import PollProduct, addForm, addFunction
+
+  def initialize(registrar):
+      registrar.registerClass(
+          PollProduct,
+          constructors=(addForm, addFunction),
+          )
+
+This function makes one call to the *registrar* object which
+registers a class as an addable object.  The *registrar* figures out
+the name to put in the product add list by looking at the 'meta_type'
+of the class.  Zope also deduces a permission based on the class's
+meta-type, in this case *Add Polls* (Zope automatically pluralizes
+"Poll" by adding an "s").  The 'constructors' argument is a tuple of
+objects consisting of two functions: an add form which is called when
+a user selects the object from the product add list, and the add
+method which is the method called by the add form.  Note that these
+functions are protected by the constructor permission.
+
+Note that you cannot restrict which types of containers can contain
+instances of your classes.  In other words, when you register a
+class, it will appear in the product add list in folders if the user
+has the constructor permission.
+
+See the *API Reference* for more information on the
+``ProductRegistrar`` interface.
+
+Factories and Constructors
+--------------------------
+
+Factories allow you to create Zope objects that can be added to
+folders and other object managers.  Factories are discussed in
+Chapter 12 of the *Zope Book*.  The basic work a factory does is to
+put a name into the product add list and associate a permission and
+an action with that name.  If you have the required permission then
+the name will appear in the product add list, and when you select the
+name from the product add list, the action method will be called.
+
+Products use Zope factory capabilities to allow instances of product
+classes to be created with the product add list.  In the above
+example of product initialization you saw how a factory is created by
+the product registrar.  Now let's see how to create the add form and
+the add list.
+
+The add form is a function that returns an HTML form that allows a
+users to create an instance of your product class.  Typically this
+form collects that id and title of the instance along with other
+relevant data.  Here's a very simple add form function for the poll
+class::
+
+  def addForm():
+      """Returns an HTML form."""
+      return """<html>
+      <head><title>Add Poll</title></head>
+      <body>
+      <form action="addFunction">
+      id <input type="type" name="id"><br>
+      question <input type="type" name="question"><br>
+      responses (one per line)
+      <textarea name="responses:lines"></textarea>
+      </form>
+      </body>
+      </html>"""
+
+Notice how the action of the form is ``addFunction``.  Also notice
+how the lines of the response are marshalled into a sequence.  See
+Chapter 2 for more information about argument marshalling and object
+publishing.
+
+It's also important to include a HTML ``head`` tag in the add form.
+This is necessary so that Zope can set the base URL to make sure that
+the relative link to the ``addFunction`` works correctly.
+
+The add function will be passed a ``FactoryDispatcher`` as its first
+argument which proxies the location (usually a Folder) where your
+product was added.  The add function may also be passed any form
+variables which are present in your add form according to normal
+object publishing rules.
+
+Here's an add function for your poll class::
+
+  def addFunction(dispatcher, id, question, responses):
+      """Create a new poll and add it to myself
+      """
+      p = PollProduct(id, question, responses)
+      dispatcher.Destination()._setObject(id, p)
+
+The dispatcher has three methods:
+
+- ``Destination`` -- The ``ObjectManager`` where your product was added.
+
+- ``DestinationURL`` -- The URL of the ``ObjectManager`` where your
+  product was added.
+
+- ``manage_main`` -- Redirects to a management view of the
+  ``ObjectManager`` where your product was added.
+
+Notice how it calls the ``_setObject()`` method of the destination
+``ObjectManager`` class to add the poll to the folder.  See the *API
+Reference* for more information on the ``ObjectManager`` interface.
+
+The add function should also check the validity of its input.  For
+example the add function should complain if the question or response
+arguments are not of the correct type.
+
+Finally you should recognize that the constructor functions are *not*
+methods on your product class.  In fact they are called before any
+instances of your product class are created.  The constructor
+functions are published on the web so they need to have doc strings,
+and are protected by a permission defined in during product
+initialization.
+
+Testing
+-------
+
+Now you're ready to register your product with Zope.  You need to add
+the add form and add method to the poll module.  Then you should
+create a `Poll` directory in your `lib/python/Products` directory and
+add the `Poll.py`, `PollProduct.py`, and `__init__.py` files.  Then
+restart Zope.
+
+Now login to Zope as a manager and visit the web management
+interface.  You should see a 'Poll' product listed inside the
+*Products* folder in the *Control_Panel*.  If Zope had trouble
+initializing your product you will see a traceback here.  Fix your
+problems, if any and restart Zope.  If you are tired of all this
+restarting, take a look at the *Refresh* facility covered in Chapter
+7.
+
+Now go to the root folder.  Select *Poll* from the product add list.
+Notice how you are taken to the add form.  Provide an id, a question,
+and a list of responses and click *Add*.  Notice how you get a black
+screen.  This is because your add method does not return anything.
+Notice also that your poll has a broken icon, and only has the
+management views.  Don't worry about these problems now, you'll find
+out how to fix these problems in the next section.
+
+Now you should build some DTML Methods and Python Scripts to test
+your poll instance.  Here's a Python Script to figure out voting
+percentages::
+
+  ## Script (Python) "getPercentFor"
+  ##parameters=index
+  ##
+  """Returns the percentage of the vote given a response index. Note,
+  this script should be bound a poll by acquisition context."""
+  poll = context
+  return float(poll.getVotesFor(index)) / poll.getTotalVotes()
+
+
+Here's a DTML Method that displays poll results and allows you to
+vote::
+
+  <dtml-var standard_html_header>
+
+  <h2>
+    <dtml-var getQuestion>
+  </h2>
+
+  <form> <!-- calls this dtml method -->
+
+  <dtml-in getResponses>
+    <p>
+      <input type="radio" name="index" value="&dtml-sequence-index;">
+      <dtml-var sequence-item>
+    </p>
+  </dtml-in>
+
+  <input type="submit" value=" Vote ">
+
+  </form>
+
+  <!-- process form -->
+
+  <dtml-if index>
+    <dtml-call expr="castVote(index)">
+  </dtml-if>
+
+  <!-- display results -->
+
+  <h2>Results</h2>
+
+  <p><dtml-var getTotalVotes> votes cast</p>
+
+  <dtml-in getResponses>
+    <p>
+      <dtml-var sequence-item> -
+      <dtml-var expr="getPercentFor(_.get('sequence-index'))">%
+    </p>
+  </dtml-in>
+
+  <dtml-var standard_html_footer>
+
+To use this DTML Method, call it on your poll instance.  Notice how
+this DTML makes calls to both your poll instance and the
+``getPercentFor`` Python script.
+
+At this point there's quite a bit of testing and refinement that you
+can do.  Your main annoyance will be having to restart Zope each time
+you make a change to your product class (but see Chapter 9 for
+information on how to avoid all this restarting).  If you vastly
+change your class you may break existing poll instances, and will
+need to delete them and create new ones.  See Chapter 9 for more
+information on debugging techniques which will come in handy.
+
+Building Management Interfaces
+------------------------------
+
+Now that you have a working product let's see how to beef up its user
+interface and create online management facilities.
+
+Defining Management Views
+-------------------------
+
+All Zope products can be managed through the web.  Products have a
+collection of management tabs or *views* which allow managers to
+control different aspects of the product.
+
+A product's management views are defined in the ``manage_options``
+class attribute.  Here's an example::
+
+        manage_options=(
+            {'label' : 'Edit', 'action' : 'editMethod'},
+            {'label' : 'View', 'action' : 'viewMethod'},
+            )
+
+The ``manage_options`` structure is a tuple that contains
+dictionaries.  Each dictionary defines a management view.  The view
+dictionary can have a number of items.
+
+- 'label' -- This is the name of the management view
+
+- 'action' -- This is the URL that is called when the view is
+  chosen. Normally this is the name of a method that displays a
+  management view.
+
+- 'target' -- An optional target frame to display the action. This
+  item is rarely needed.
+
+- 'help' -- Optional help information associated with the
+  view. You'll find out more about this option later.
+
+Management views are displayed in the order they are defined.
+However, only those management views for which the current user has
+permissions are displayed.  This means that different users may see
+different management views when managing your product.
+
+Normally you will define a couple custom views and reusing some
+existing views that are defined in your base classes.  Here's an
+example::
+
+  class PollProduct(..., Item):
+      ...
+
+      manage_options=(
+          {'label' : 'Edit', 'action' : 'editMethod'},
+          {'label' : 'Options', 'action' : 'optionsMethod'},
+          ) + RoleManager.manage_options + Item.manage_options
+
+This example would include the standard management view defined by
+``RoleManager`` which is *Security* and those defined by ``Item``
+which are *Undo* and *Ownership*.  You should include these standard
+management views unless you have good reason not to. If your class
+has a default view method (``index_html``) you should also include a
+*View* view whose action is an empty string.  See Chapter 2 for more
+information on ``index_html``.
+
+Note: you should not make the *View* view the first view on your
+class.  The reason is that the first management view is displayed
+when you click on an object in the Zope management interface.  If the
+*View* view is displayed first, users will be unable to navigate to
+the other management views since the view tabs will not be visible.
+
+Creating Management Views
+-------------------------
+
+The normal way to create management view methods is to use DTML.  You
+can use the ``DTMLFile`` class to create a DTML Method from a file.
+For example::
+
+  from Globals import DTMLFile
+
+  class PollProduct(...):
+    ...
+
+    editForm = DTMLFile('dtml/edit', globals())
+    ...
+
+This creates a DTML Method on your class which is defined in the
+`dtml/edit.dtml` file.  Notice that you do not have to include the
+``.dtml`` file extension.  Also, don't worry about the forward slash
+as a path separator; this convention will work fine on Windows. By
+convention DTML files are placed in a ``dtml`` subdirectory of your
+product.  The ``globals()`` argument to the ``DTMLFile`` constructor
+allows it to locate your product directory.  If you are running Zope
+in debug mode then changes to DTML files are reflected right away. In
+other words you can change the DTML of your product's views without
+restarting Zope to see the changes.
+
+DTML class methods are callable directly from the web, just like
+other methods.  So now users can see your edit form by calling the
+``editForm`` method on instances of your poll class.  Typically DTML
+methods will make calls back to your instance to gather information
+to display.  Alternatively you may decide to wrap your DTML methods
+with normal methods.  This allows you to calculate information needed
+by your DTML before you call it.  This arrangement also ensures that
+users always access your DTML through your wrapper.  Here's an
+example::
+
+  from Globals import DTMLFile
+
+  class PollProduct(...):
+    ...
+
+    _editForm = DTMLFile('dtml/edit', globals())
+
+    def editForm(self, ...):
+        ...
+
+        return self._editForm(REQUEST, ...)
+
+
+When creating management views you should include the DTML variables
+``manage_page_header`` and ``manage_tabs`` at the top, and
+``manage_page_footer`` at the bottom.  These variables are acquired
+by your product and draw a standard management view header, tabs
+widgets, and footer.  The management header also includes CSS
+information which you can take advantage of if you wish to add CSS
+style information to your management views.  The management CSS
+information is defined in the
+`lib/python/App/dtml/manage_page_style.css.dtml`` file.  Here are the
+CSS classes defined in this file and conventions for their use.
+
+- 'form-help' -- Explanatory text related to forms.  In the future,
+  users may have the option to hide this text.
+
+- 'std-text' -- Declarative text unrelated to forms.  You should
+  rarely use this class.
+
+- 'form-title' -- Form titles.
+
+- 'form-label' -- Form labels for required form elements.
+
+- 'form-optional' -- Form labels for optional form elements.
+
+- 'form-element' -- Form elements.  Note, because of a Netscape bug,
+  you should not use this class on 'textarea' elements.
+
+- 'form-text' -- Declarative text in forms.
+
+- 'form-mono' -- Fixed width text in forms.  You should rarely use
+  this class.
+
+Here's an example management view for your poll class.  It allows you
+to edit the poll question and responses (see ``editPollForm.dtml``)::
+
+  <dtml-var manage_page_header>
+  <dtml-var manage_tabs>
+
+  <p class="form-help">
+  This form allows you to change the poll's question and
+  responses. <b>Changing a poll's question and responses
+  will reset the poll's vote tally.</b>.
+  </p>
+
+  <form action="editPoll">
+  <table>
+
+    <tr valign="top">
+      <th class="form-label">Question</th>
+      <td><input type="text" name="question" class="form-element"
+      value="&dtml-getQuestion;"></td>
+    </tr>
+
+    <tr valign="top">
+      <th class="form-label">Responses</th>
+      <td><textarea name="responses:lines" cols="50" rows="10">
+      <dtml-in getResponses>
+      <dtml-var sequence-item html_quote>
+      </dtml-in>
+      </textarea>
+      </td>
+    </tr>
+
+    <tr>
+      <td></td>
+      <td><input type="submit" value="Change" class="form-element"></td>
+    </tr>
+
+  </table>
+  </form>
+
+  <dtml-var manage_page_header>
+
+This DTML method displays an edit form that allows you to change the
+questions and responses of your poll.  Notice how poll properties are
+HTML quoted either by using ``html_quote`` in the ``dtml-var`` tag,
+or by using the ``dtml-var`` entity syntax.
+
+Assuming this DTML is stored in a file ``editPollForm.dtml`` in your
+product's ``dtml`` directory, here's how to define this method on
+your class::
+
+  class PollProduct(...):
+      ...
+
+      security.declareProtected('View management screens', 'editPollForm')
+      editPollForm = DTML('dtml/editPollForm', globals())
+
+Notice how the edit form is protected by the `View management
+screens` permission.  This ensures that only managers will be able to
+call this method.
+
+Notice also that the action of this form is ``editPoll``.  Since the
+poll as it stands doesn't include any edit methods you must define
+one to accept the changes.  Here's an ``editPoll`` method::
+
+  class PollProduct(...):
+      ...
+
+      def __init__(self, id, question, responses):
+          self.id = id
+          self.editPoll(question, response)
+
+      ...
+
+      security.declareProtected('Change Poll', 'editPoll')
+      def editPoll(self, question, responses):
+          """
+          Changes the question and responses.
+          """
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+
+Notice how the ``__init__`` method has been refactored to use the new
+``editPoll`` method.  Also notice how the ``editPoll`` method is
+protected by a new permissions, ``Change Poll``.
+
+There still is a problem with the ``editPoll`` method.  When you call
+it from the ``editPollForm`` through the web nothing is returned.
+This is a bad management interface.  You want this method to return
+an HTML response when called from the web, but you do not want it to
+do this when it is called from ``__init__``.  Here's the solution::
+
+  class Poll(...):
+      ...
+
+      def editPoll(self, question, responses, REQUEST=None):
+          """Changes the question and responses."""
+          self._question = question
+          self._responses = responses
+          self._votes = {}
+          for i in range(len(responses)):
+              self._votes[i] = 0
+          if REQUEST is not None:
+              return self.editPollForm(REQUEST,
+                  manage_tabs_message='Poll question and responses changed.')
+
+If this method is called from the web, then Zope will automatically
+supply the ``REQUEST`` parameter.  (See chapter 4 for more
+information on object publishing).  By testing the ``REQUEST`` you
+can find out if your method was called from the web or not.  If you
+were called from the web you return the edit form again.
+
+A management interface convention that you should use is the
+``manage_tab_message`` DTML variable.  If you set this variable when
+calling a management view, it displays a status message at the top of
+the page.  You should use this to provide feedback to users
+indicating that their actions have been taken when it is not obvious.
+For example, if you don't return a status message from your
+``editPoll`` method, users may be confused and may not realize that
+their changes have been made.
+
+Sometimes when displaying management views, the wrong tab will be
+highlighted.  This is because 'manage_tabs' can't figure out from the
+URL which view should be highlighted.  The solution is to set the
+'management_view' variable to the label of the view that should be
+highlighted.  Here's an example, using the 'editPoll' method::
+
+  def editPoll(self, question, responses, REQUEST=None):
+      """
+      Changes the question and responses.
+      """
+      self._question = question
+      self._responses = responses
+      self._votes = {}
+      for i in range(len(responses)):
+          self._votes[i] = 0
+      if REQUEST is not None:
+          return self.editPollForm(REQUEST,
+              management_view='Edit',
+              manage_tabs_message='Poll question and responses changed.')
+
+Now let's take a look a how to define an icon for your product.
+
+Icons
+-----
+
+Zope products are identified in the management interface with icons.
+An icon should be a 16 by 16 pixel GIF image with a transparent
+background.  Normally icons files are located in a ``www``
+subdirectory of your product package.  To associate an icon with a
+product class, use the ``icon`` parameter to the ``registerClass``
+method in your product's constructor.  For example::
+
+  def initialize(registrar):
+      registrar.registerClass(
+          PollProduct,
+          constructors=(addForm, addFunction),
+          icon='www/poll.gif'
+          )
+
+Notice how in this example, the icon is identified as being within
+the product's ``www`` subdirectory.
+
+See the *API Reference* for more information on the ``registerClass``
+method of the ``ProductRegistrar`` interface.
+
+Online Help
+-----------
+
+Zope has an online help system that you can use to provide help for
+your products.  Its main features are context-sensitive help and API
+help.  You should provide both for your product.
+
+
+Context Sensitive Help
+----------------------
+
+To create context sensitive help, create one help file per management
+view in your product's ``help`` directory.  You have a choice of
+formats including: HTML, DTML, structured text, GIF, JPG, and PNG.
+
+Register your help files at product initialization with the
+``registerHelp()`` method on the registrar object::
+
+  def initialize(registrar):
+      ...
+      registrar.registerHelp()
+
+This method will take care of locating your help files and creating
+help topics for each help file.  It can recognize these file
+extensions: ``.html``, ``.htm``, ``.dtml``, ``.txt``, ``.stx``,
+``.gif``, ``.jpg``, ``.png``.
+
+If you want more control over how your help topics are created you
+can use the ``registerHelpTopic()`` method which takes an id and a
+help topic object as arguments.  For example::
+
+  from mySpecialHelpTopics import MyTopic
+
+  def initialize(context):
+      ...
+      context.registerHelpTopic('myTopic', MyTopic())
+
+Your help topic should adhere to the 'HelpTopic' interface. See the
+*API Reference* for more details.
+
+The chief way to bind a help topic to a management screen is to
+include information about the help topic in the class's
+manage_options structure. For example::
+
+  manage_options = (
+      {'label': 'Edit',
+       'action': 'editMethod',
+       'help': ('productId','topicId')},
+      )
+
+The `help` value should be a tuple with the name of your product's
+Python package, and the file name (or other id) of your help topic.
+Given this information, Zope will automatically draw a *Help* button
+on your management screen and link it to your help topic.
+
+To draw a help button on a management screen that is not a view (such
+as an add form), use the 'HelpButton' method of the 'HelpSys' object
+like so::
+
+  <dtml-var "HelpSys.HelpButton('productId', 'topicId')">
+
+This will draw a help button linked to the specified help topic.  If
+you prefer to draw your own help button you can use the helpURL
+method instead like so::
+
+  <dtml-var "HelpSys.helpURL(
+    topic='productId',
+    product='topicId')">
+
+This will give you a URL to the help topic.  You can choose to draw
+whatever sort of button or link you wish.
+
+Other User Interfaces
+---------------------
+
+In addition to providing a through the web management interface your
+products may also support many other user interfaces.  You product
+might have no web management interfaces, and might be controlled
+completely through some other network protocol.  Zope provides
+interfaces and support for FTP, WebDAV and XML-RPC.  If this isn't
+enough you can add other protocols.
+
+FTP and WebDAV Interfaces
+-------------------------
+
+Both FTP and WebDAV treat Zope objects like files and
+directories.  See Chapter 3 for more information on FTP and WebDAV.
+
+By simply sub-classing from 'SimpleItem.Item' and 'ObjectManager' if
+necessary, you gain basic FTP and WebDAV support.  Without any work
+your objects will appear in FTP directory listings and if your class
+is an 'ObjectManager' its contents will be accessible via FTP and
+WebDAV.  See Chapter 2 for more information on implementing FTP and
+WebDAV support.
+
+XML-RPC and Network Services
+----------------------------
+
+XML-RPC is covered in Chapter 2.  All your product's methods can be
+accessible via XML-RPC.  However, if your are implementing network
+services, you should explicitly plan one or more methods for use with
+XML-RPC.
+
+Since XML-RPC allows marshalling of simple strings, lists, and
+dictionaries, your XML-RPC methods should only accept and return
+these types.  These methods should never accept or return Zope
+objects.  XML-RPC also does not support 'None' so you should use zero
+or something else in place of 'None'.
+
+Another issue to consider when using XML-RPC is security.  Many
+XML-RPC clients still don't support HTTP basic authorization.
+Depending on which XML-RPC clients you anticipate, you may wish to
+make your XML-RPC methods public and accept authentication
+credentials as arguments to your methods.
+
+Content Management Framework Interface
+--------------------------------------
+
+The `Content Management Framework <http://cmf.zope.org>`_ is an
+evolving content management extension for Zope.  It provides a number
+of interfaces and conventions for content objects.  If you wish to
+support the CMF you should consult the CMF user interface guidelines
+and interface documentation.
+
+Supporting the CMF interfaces is not a large burden if you already
+support the Zope management interface.  You should consider
+supporting the CMF if your product class handles user manageable
+content such as documents, images, business forms, etc.
+
+Packaging Products
+------------------
+
+Zope products are normally packaged as tarballs.  You should create
+your product tarball in such a way as to allow it to be unpacked in
+the Products directory.  For example, `cd` to the Products directory
+and then issue a `tar` comand like so::
+
+  $ tar zcvf MyProduct-1.0.1.tgz MyProduct
+
+This will create a gzipped tar archive containing your product.  You
+should include your product name and version number in file name of
+the archive.
+
+See the `Poll-1.0.tgz <examples/Poll-1.0.tgz>`_ file for an example
+of a fully packaged Python product.
+
+
+Product Information Files
+-------------------------
+
+Along with your Python and ZPT files you should include some
+information about your product in its root directory.
+
+- `README.txt` -- Provides basic information about your product.
+   Zope will parse this file as StructuredText and make it available
+   on the *README* view of your product in the control panel.
+
+- `VERSION.txt` -- Contains the name and version of your product on a
+  single line. For example, 'Multiple Choice Poll 1.1.0'.  Zope will
+  display this information as the 'version' property of your product
+  in the control panel.
+
+- `LICENSE.txt` -- Contains your product license, or a link to it.
+
+You may also wish to provide additional information.  Here are some
+suggested optional files to include with your product.
+
+- `INSTALL.txt` -- Provides special instructions for installing the
+  product and components on which it depends.  This file is only
+  optional if your product does not require more than an ungzip/untar
+  into a Zope installation to work.
+
+- `TODO.txt` -- This file should make clear where this product
+  release needs work, and what the product author intends to do about
+  it.
+
+- `CHANGES.txt` and `HISTORY.txt` -- 'CHANGES.txt' should enumerate
+  changes made in particular product versions from the last release
+  of the product. Optionally, a 'HISTORY.txt' file can be used for
+  older changes, while 'CHANGES.txt' lists only recent changes.
+
+- `DEPENDENCIES.txt` -- Lists dependencies including required os
+  platform, required Python version, required Zope version, required
+  Python packages, and required Zope products.
+
+Product Directory Layout
+------------------------
+
+By convention your product will contain a number of sub-directories.
+Some of these directories have already been discussed in this
+chapter. Here is a summary of them.
+
+- `www` -- Contains your icon & ZPT files.
+
+- `help` -- Contains your help files.
+
+- `tests` -- Contains your unit tests.
+
+It is not necessary to include these directories if your don't have
+anything to go in them.
+
+Evolving Products
+=================
+
+As you develop your product classes you will generally make a series
+of product releases.  While you don't know in advance how your
+product will change, when it does change there are measures that you
+can take to minimize problems.
+
+Evolving Classes
+----------------
+
+Issues can occur when you change your product class because instances
+of these classes are generally persistent.  This means that instances
+created with an old class will start using a new class.  If your
+class changes drastically this can break existing instances.
+
+The simplest way to handle this situation is to provide class
+attributes as defaults for newly added attributes.  For example if
+the latest version of your class expects an 'improved_spam' instance
+attribute while earlier versions only sported 'spam' attributes, you
+may wish to define an 'improved_spam' class attribute in your new
+class so your old objects won't break when they run with your new
+class.  You might set 'improved_spam' to None in your class, and in
+methods where you use this attribute you may have to take into
+account that it may be None.  For example::
+
+  class Sandwich(...):
+
+      improved_spam = None
+      ...
+
+      def assembleSandwichMeats(self):
+          ...
+          # test for old sandwich instances
+          if self.improved_spam is None:
+              self.updateToNewSpam()
+          ...
+
+Another solution is to use the standard Python pickling hook
+'__setstate__', however, this is in general more error prone and
+complex.
+
+A third option is to create a method to update old instances.  Then
+you can manually call this method on instances to update to them.
+Note, this won't work unless the instances function well enough to be
+accessible via the Zope management screens.
+
+While you are developing a product you won't have to worry too much
+about these details, since you can always delete old instances that
+break with new class definitions.  However, once you release your
+product and other people start using it, then you need to start
+planning for the eventuality of upgrading.
+
+Another nasty problem that can occur is breakage caused by renaming
+your product classes.  You should avoid this since it breaks all
+existing instances.  If you really must change your class name,
+provide aliases to it using the old name.  You may however, change
+your class's base classes without causing these kinds of problems.
+
+Evolving Interfaces
+-------------------
+
+The basic rule of evolving interfaces is *don't do it*.  While you
+are working privately you can change your interfaces all you wish.
+But as soon as you make your interfaces public you should freeze
+them.  The reason is that it is not fair to users of your interfaces
+to changes them after the fact.  An interface is contract.  It
+specifies how to use a component and it specifies how to implement
+types of components.  Both users and developers will have problems if
+your change the interfaces they are using or implementing.
+
+The general solution is to create simple interfaces in the first
+place, and create new ones when you need to change an existing
+interface.  If your new interfaces are compatible with your existing
+interfaces you can indicate this by making your new interfaces extend
+your old ones.  If your new interface replaces an old one but does
+not extend it you should give it a new name such as,
+``WidgetWithBellsOn``.  Your components should continue to support
+the old interface in addition to the new one for a few releases.
+
+Conclusion
+==========
+
+Migrating your components into fully fledged Zope products is a
+process with a number of steps.  There are many details to keep track
+of.  However, if you follow the recipe laid out in this chapter you
+should have no problems.
+
+Zope products are a powerful framework for building web applications.
+By creating products you can take advantage of Zope's features
+including security, scalability, through the web management, and
+collaboration.

Copied: zope2docs/branches/baijum-reorganize/zdgbook/Security.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/Security.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/Security.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/Security.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,1300 @@
+########
+Security
+########
+
+Introduction
+============
+
+A typical web application needs to be securely managed.  Different
+types of users need different kinds of access to the components that
+make up an application. To this end, Zope includes a comprehensive
+set of security features.  This chapter's goal is to shed light on
+Zope security in the context of Zope Product development.  For a more
+fundamental overview of Zope security, you may wish to refer to the
+*Zope Book*, Chapter 6, Users and Security.  Before diving into this
+chapter, you should have a basic understanding of how to build Zope
+Products as well as an understanding of how the Zope object publisher
+works. These topics are covered in Chapter 2 and Chapter 3,
+respectively.
+
+
+Security Architecture
+=====================
+
+The Zope security architecture is built around a *security policy*,
+which you can think of as the "access control philosophy" of
+Zope. This policy arbitrates the decisions Zope makes about whether
+to allow or deny access to any particular object defined within the
+system.
+
+How The Security Policy Relates to Zope's Publishing Machinery
+--------------------------------------------------------------
+
+When access to Zope is performed via HTTP, WebDAV, or FTP, Zope's
+publishing machinery consults the security policy in order to
+determine whether to allow or deny access to a visitor for a
+particular object.  For example, when a user visits the root
+'index_html' object of your site via HTTP, the security policy is
+consulted by 'ZPublisher' to determine whether the user has
+permission to view the 'index_html' object itself.  For more
+information on this topic, see Chapter 3, "Object Publishing".
+
+The Zope security policy is consulted when an object is accessed the
+publishing machinery, for example when a web request is submitted.
+
+
+How The Security Policy Relates to Restricted Code
+--------------------------------------------------
+
+*Restricted code* is generally any sort of logic that may be edited
+remotely (through the Web, FTP, via WebDAV or by other means). DTML
+Methods, SQLMethods, Python Scripts and Perl Scripts are examples of
+restricted code.
+
+When restricted code runs, any access to objects integrated with Zope
+security is arbitrated by the security policy. For example if you
+write a bit of restricted code with a line that attempts to
+manipulate an object you don't have sufficient permission to use, the
+security policy will deny you access to the object.  This generally
+is accomplished by raising an 'Unauthorized' exception, which is a
+Python string exception caught by a User Folder which signifies that
+Zope should attempt to get user credentials before obeying the
+request.  The particular code used to attempt to obtain the
+credentials is determined by the User Folder "closest" (folder-wise)
+to the object being accessed.
+
+The Zope security policy is consulted when an object is accessed by
+restricted code.
+
+'Unauthorized' Exceptions and Through-The-Web Code
+--------------------------------------------------
+
+The security policy infrastructure will raise an 'Unauthorized'
+exception automatically when access to an object is denied.  When an
+'Unauthorized' exception is raised within Zope, it is handled in a
+sane way by Zope, generally by having the User Folder prompt the user
+for login information.  Using this functionality, it's possible to
+protect Zope objects through access control, only prompting the user
+for authentication when it is necessary to perform an action which
+requires privilege.
+
+An example of this behavior can be witnessed within the Zope
+Management interface itself.  The management interface prompts you to
+log in when visiting, for example, the '/manage' method of any Zope
+object.  This is due to the fact that an anonymous user does not
+generally possess the proper credentials to use the management
+interface.  If you're using Zope in the default configuration with
+the default User Folder, it prompts you to provide login information
+via an HTTP basic authentication dialog.
+
+How The Security Policy Relates To Unrestricted Code
+----------------------------------------------------
+
+There are also types of *unrestricted code* in Zope, where the logic
+is not constrained by the security policy. Examples of unrestricted
+code are the methods of Python classes that implement the objects in
+Python file-based add-on components.  Another example of unrestricted
+code can be found in External Method objects, which are defined in
+files on the filesystem.  These sorts of code are allowed to run
+"unrestricted" because access to the file system is required to
+define such logic.  Zope assumes that code defined on the filesystem
+is "trusted", while code defined "through the web" is not.  All
+filesystem-based code in Zope is unrestricted code.
+
+We'll see later that while the security policy does not constrain
+what your unrestricted code does, it can and should be used to
+control the ability to *call* your unrestricted code from within a
+restricted-code environment.
+
+The Zope security policy is *not* consulted when unrestricted code is
+run.
+
+Details Of The Default Zope Security Policy
+-------------------------------------------
+
+In short, the default Zope security policy ensures the following:
+
+- access to an object which does not have any associated security
+  information is always denied.
+
+- if an object is associated with a permission, access is granted or
+  denied based on the user's roles.  If a user has a role which has
+  been granted the permission in question, access is granted.  If the
+  user does not possess a role that has been granted the permission
+  in question, access is denied.
+
+- if the object has a security assertion declaring it *public* , then
+  access will be granted.
+
+- if the object has a security assertion declaring it *private*, then
+  access will be denied.
+
+- accesses to objects that have names beginning with the underscore
+  character '_' are always denied.
+
+As we delve further into Zope security within this chapter, we'll see
+exactly what it means to associate security information with an
+object.
+
+
+Overview Of Using Zope Security Within Your Product
+---------------------------------------------------
+
+Of course, now that we know what the Zope security policy is, we need
+to know how our Product can make use of it.  Zope developers leverage
+the Zope security policy primarily by making security declarations
+related to methods and objects within their Products.  Using security
+assertions, developers may deny or allow all types of access to a
+particular object or method unilaterally, or they may protect access
+to Zope objects more granularly by using permissions to grant or deny
+access based on the roles of the requesting user to the same objects
+or methods.
+
+
+For a more fundamental overview of Zope users, roles, and
+permissions, see the section titled "Authorization and Managing
+Security" in the Security Chapter of the *Zope Book*.
+
+Security Declarations In Zope Products
+--------------------------------------
+
+Zope security declarations allow developers to make security
+assertions about a Product-defined object and its methods.
+Security declarations come in three basic forms.  These are:
+
+- public -- allow anybody to access the protected object
+  or method
+
+- private -- deny anyone access to the protected object or
+  method
+
+- protected -- protect access to the object or method via a
+  permission
+
+We'll see how to actually "spell" these security assertions a
+little later in this chapter.  In the meantime, just know that
+security declarations are fundamental to Zope Product security,
+and they can be used to protect access to an object by
+associating it with a permission.  We will refer to security
+declarations as "declarations" and "assertions" interchangeably
+within this chapter.
+
+
+Permissions In Zope Products
+============================
+
+A permission is the smallest unit of access to an object in Zope,
+roughly equivalent to the atomic permissions on files seen in Windows
+NT or UNIX: R (Read), W(Write), X(Execute), etc. However, unlike
+these types of mnemonic permissions shared by all sorts of different
+file types in an operating system product, in Zope, a permission
+usually describes a fine-grained logical operation which takes place
+upon an object, such as "View Management Screens" or "Add
+Properties".
+
+Zope administrators associate these permissions with *roles*, which
+they grant to Zope users.  Thus, declaring a protection assertion on
+a method of "View management screens" ensures that only users who
+possess roles which have been granted the "View management screens"
+permission are able to perform the action that the method defines.
+
+It is important to note that Zope's security architecture dictates
+that roles and users remain the domain of administrators, while
+permissions remain the domain of developers.  Developers of Products
+should not attempt to define roles or users, although they may (and
+usually must) define permissions.  Most importantly, a Zope
+administrator who makes use of your product should have the "last
+word" as regards which roles are granted which permissions, allowing
+her to protect her site in a manner that fits her business goals.
+
+Permission names are strings, and these strings are currently
+arbitrary.  There is no permission hierarchy, or list of "approved
+permissions".  Developers are encouraged to reuse Zope core
+permissions (e.g. "View", "Access contents information") when
+appropriate, or they may create their own as the need arises.  It is
+generally wise to reuse existing Zope permission names unless you
+specifically need to define your own.  For a list of existing Zope
+core permissions, see Appendix A, "Zope Core Permissions".
+
+Permissions are often tied to method declarations in Zope.  Any
+number of method declarations may share the same permission.  It's
+useful to declare the same permission on a set of methods which can
+logically be grouped together.  For example, two methods which return
+management forms for the object can be provided with the same
+permission, "View management screens".  Likewise, two entirely
+different objects can share a permission name to denote that the
+operation that's being protected is fundamentally similar.  For
+instance, most Product-defined objects reuse the Zope "View"
+permission, because most Zope objects need to be viewed in a web
+browser.  If you create an addable Zope class named 'MyObject', it
+doesn't make much sense to create a permission "View MyObject",
+because the generic "View" permission may be reused for this action.
+
+There is an exception to the "developers should not try to define
+roles" rule inasmuch as Zope allows developers to assign "default
+roles" to a permission.  This is primarily for the convenience of the
+Zope administrator, as default roles for a permission cause the Zope
+security machinery to provide a permission to a role *by default*
+when instances of a Product class are encountered during security
+operations.  For example, if your Product defines a permission "Add
+Poll Objects", this permission may be associated with a set of
+default roles, perhaps "Manager".  Default roles in Products should
+not be used against roles other than "Manager", "Anonymous", "Owner",
+and "Authenticated" (the four default Zope roles), as other roles are
+not guaranteed to exist in every Zope installation.
+
+Using security assertions in Zope is roughly analogous to assigning
+permission bit settings and ownership information to files in a UNIX
+or Windows filesystem.  Protecting objects via permissions allows
+developers and administrators to secure Zope objects independently of
+statements made in application code.
+
+Implementing Security In Python Products
+========================================
+
+Security Assertions
+-------------------
+
+You may make several kinds of security assertions at the Python
+level.  You do this to declare accessibility of methods and
+subobjects of your classes. Three of the most common assertions that
+you'll want to make on your objects are:
+
+- this object is **public** (always accessible)
+
+- this object is **private** (not accessible by restricted code or by
+  URL traversal)
+
+- this object is **protected** by a specific permission
+
+There are a few other kinds of security assertions that are 
+much less frequently used but may be needed in some cases:
+
+- asserting that access to subobjects that do not have explicit
+  security information should be allowed rather than denied.
+
+- asserting what sort of protection should be used when determining
+  access to an *object itself* rather than a particular method of the
+  object
+
+It is important to understand that security assertions made in your
+Product code *do not* limit the ability of the code that the
+assertion protects.  Assertions only protect *access to this code*.
+The code which constitutes the body of a protected, private, or
+public method of a class defined in a Zope disk-based Product runs
+completely unrestricted, and is not subject to security constraints
+of any kind within Zope.  An exception to this rule occurs when
+disk-based-Product code calls a "through the web" method such as a
+Python Script or a DTML Method.  In this case, the security
+constraints imposed by these objects respective to the current
+request are obeyed.
+
+When Should I Use Security Assertions?
+--------------------------------------
+
+If you are building an object that will be used from DTML or other
+restricted code, or that will be accessible directly through the web
+(or other remote protocols such as FTP or WebDAV) then you need to
+define security information for your object.
+
+Making Security Assertions
+--------------------------
+
+As a Python developer, you make security assertions in your Python
+classes using 'SecurityInfo' objects. A 'SecurityInfo' object
+provides the interface for making security assertions about an object
+in Zope.
+
+The convention of placing security declarations inside Python code
+may at first seem a little strange if you're used to "plain old
+Python" which has no notion at all of security declarations.  But
+because Zope provides the ability to make these security assertions
+at such a low level, the feature is ubiquitous throughout Zope,
+making it easy to make these declarations once in your code, usable
+site-wide without much effort.
+
+Class Security Assertions
+=========================
+
+The most common kind of 'SecurityInfo' you will use as a component
+developer is the 'ClassSecurityInfo' object.  You use
+'ClassSecurityInfo' objects to make security assertions about methods
+on your classes.
+
+Classes that need security assertions are any classes that define
+methods that can be called "through the web".  This means any methods
+that can be called directly with URL traversal, from DTML Methods, or
+from Python-based Script objects.
+
+Declaring Class Security
+------------------------
+
+When writing the classes in your product, you create a
+'ClassSecurityInfo' instance *within each class that needs to play
+with the security model*. You then use the 'ClassSecurityInfo' object
+to make assertions about your class, its subobjects and its methods.
+
+The 'ClassSecurityInfo' class is defined in the 'AccessControl'
+package of the Zope framework. To declare class security information
+create a 'ClassSecurityInfo' class attribute named 'security'.  The
+name 'security' is used for consistency and for the benefit of new
+component authors, who often learn from looking at other people's
+code. You do not have to use the name 'security' for the security
+infrastructure to recognize your assertion information, but it is
+recommended as a convention.  For example::
+
+  from AccessControl import ClassSecurityInfo
+
+  class Mailbox(ObjectManager):
+    """A mailbox object that contains mail message objects."""
+
+    # Create a SecurityInfo for this class. We will use this 
+    # in the rest of our class definition to make security 
+    # assertions.
+    security = ClassSecurityInfo()
+
+    # Here is an example of a security assertion. We are 
+    # declaring that access to messageCount is public.
+    security.declarePublic('messageCount')
+
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+
+Note that in the example above we called the 'declarePublic' method
+of the 'ClassSecurityInfo' instance to declare that access to the
+'messageCount' method be public. To make security assertions for your
+object, you just call the appropriate methods of the
+'ClassSecurityInfo' object, passing the appropriate information for
+the assertion you are making.
+
+'ClassSecurityInfo' approach has a number of benefits. A major
+benefit is that it is very explicit, it allows your security
+assertions to appear in your code near the objects they protect,
+which makes it easier to assess the state of protection of your code
+at a glance. The 'ClassSecurityInfo' interface also allows you as a
+component developer to ignore the implementation details in the
+security infrastructure and protects you from future changes in those
+implementation details.
+
+Let's expand on the example above and see how to make the most common
+security assertions using the 'SecurityInfo' interface.
+
+To assert that a method is *public* (anyone may call it) you may call
+the 'declarePublic' method of the 'SecurityInfo' object, passing the
+name of the method or subobject that you are making the assertion
+on::
+
+  security.declarePublic(methodName)
+
+To assert that a method is *private* you call the 'declarePrivate'
+method of the 'SecurityInfo' object, passing the name of the method
+or subobject that you are making the assertion on::
+
+  security.declarePrivate(methodName)
+
+To assert that a method or subobject is *protected* by a particular
+permission, you call the 'declareProtected' method of the
+'SecurityInfo' object, passing a permission name and the name of a
+method to be protected by that permission::
+
+  security.declareProtected(permissionName, methodName)
+
+If you have lots of methods you want to protect under the same
+permission, you can pass as many methodNames ase you want::
+
+  security.declareProtected(permissionName, methodName1,
+  methodName2, methodName3, ...)
+
+Passing multiple names like this works for all of the 'declare'
+security methods ('declarePublic', 'declarePrivate', and
+'declareProtected').
+
+Deciding To Use 'declareProtected' vs. 'declarePublic' or 'declarePrivate'
+--------------------------------------------------------------------------
+
+      If the method you're making the security declaration against is
+      innocuous, and you're confident that its execution will not
+      disclose private information nor make inappropriate changes to
+      system state, you should declare the method public.
+
+      If a method should never be run under any circumstances via
+      traversal or via through-the-web code, the method should be
+      declared private.  This is the default if a method has no
+      security assertion, so you needn't explicitly protect
+      unprotected methods unless you've used 'setDefaultAccess' to set
+      the object's default access policy to 'allow' (detailed in
+      *Other Assertions*, below).
+
+      If the method should only be executable by a certain class of
+      users, you should declare the method protected.
+
+A Class Security Example
+------------------------
+
+Let's look at an expanded version of our 'Mailbox' example that makes
+use of each of these types of security assertions::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class Mailbox(ObjectManager):
+    """A mailbox object."""
+
+  # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    security.declareProtected('View management screens', 'manage')
+    manage=HTMLFile('mailbox_manage', globals())
+
+    security.declarePublic('messageCount')
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+    # protect 'listMessages' with the 'View Mailbox' permission
+    security.declareProtected('View Mailbox', 'listMessages')
+
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.declarePrivate('getMessages')
+    def getMessages(self):
+      self._messages=GoGetEm()
+      return self._messages
+
+  # call this to initialize framework classes, which
+  # does the right thing with the security assertions.
+  Globals.InitializeClass(Mailbox)
+
+Note the last line in the example.  In order for security assertions
+to be correctly applied to your class, you must call the global class
+initializer ('Globals.InitializeClass') for all classes that have
+security information. This is very important - the global initializer
+does the "dirty work" required to ensure that your object is
+protected correctly based on the security assertions that you have
+made. If you don't run it on the classes that you've protected with
+security assertions, the security assertions will not be effective.
+
+Deciding Permission Names For Protected Methods
+-----------------------------------------------
+
+When possible, you should make use of an existing Zope permission
+within a 'declareProtected' assertion.  A list of the permissions
+which are available in a default Zope installation is available
+within Appendix A.  When it's not possible to reuse an existing
+permission, you should choose a permission name which is a verb or a
+verb phrase.
+
+Object Assertions
+-----------------
+
+Often you will also want to make a security assertion on the *object
+itself*. This is important for cases where your objects may be
+accessed in a restricted environment such as DTML. Consider the
+example DTML code::
+
+  <dtml-var expr="some_method(someObject)">
+
+Here we are trying to call 'some_method', passing the object
+'someObject'. When this is evaluated in the restricted DTML
+environment, the security policy will attempt to validate access to
+both 'some_method' and 'someObject'. We've seen how to make
+assertions on methods - but in the case of 'someObject' we are not
+trying to access any particular method, but rather the *object
+itself* (to pass it to 'some_method'). Because the security machinery
+will try to validate access to 'someObject', we need a way to let the
+security machinery know how to handle access to the object itself in
+addition to protecting its methods.
+
+To make security assertions that apply to the *object itself* you
+call methods on the 'SecurityInfo' object that are analogous to the
+three that we have already seen::
+
+  security.declareObjectPublic()
+
+  security.declareObjectPrivate()
+
+  security.declareObjectProtected(permissionName)
+
+The meaning of these methods is the same as for the method variety,
+except that the assertion is made on the object itself.
+
+An Object Assertion Example
+---------------------------
+
+Here is the updated 'Mailbox' example, with the addition of a
+security assertion that protects access to the object itself with the
+'View Mailbox' permission::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class Mailbox(ObjectManager):
+    """A mailbox object."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    # Set security for the object itself
+    security.declareObjectProtected('View Mailbox')
+
+    security.declareProtected('View management screens', 'manage')
+    manage=HTMLFile('mailbox_manage', globals())
+
+    security.declarePublic('messageCount')
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+    # protect 'listMessages' with the 'View Mailbox' permission
+    security.declareProtected('View Mailbox', 'listMessages')
+
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.declarePrivate('getMessages')
+    def getMessages(self):
+      self._messages=GoGetEm()
+      return self._messages
+
+  # call this to initialize framework classes, which
+  # does the right thing with the security assertions.
+  Globals.InitializeClass(Mailbox)
+
+Other Assertions
+----------------
+
+The SecurityInfo interface also supports the less common
+security assertions noted earlier in this document.
+
+To assert that access to subobjects that do not have explicit
+security information should be *allowed* rather than *denied* by
+the security policy, use::
+
+  security.setDefaultAccess("allow")
+
+This assertion should be used with caution. It will effectively
+change the access policy to "allow-by-default" for all
+attributes in your object instance (not just class attributes)
+that are not protected by explicit assertions.  By default, the
+Zope security policy flatly denies access to attributes and
+methods which are not mentioned within a security assertion.
+Setting the default access of an object to "allow" effectively
+reverses this policy, allowing access to all attributes and
+methods which are not explicitly protected by a security
+assertion.
+
+'setDefaultAccess' applies to attributes that are simple Python
+types as well as methods without explicit protection. This is
+important because some mutable Python types (lists, dicts) can
+then be modified by restricted code. Setting default access to
+"allow" also affects attributes that may be defined by the base
+classes of your class, which can lead to security holes if you
+are not sure that the attributes of your base classes are safe
+to access.
+
+Setting the default access to "allow" should only be done if you
+are sure that all of the attributes of your object are safe to
+access, since the current architecture does not support using
+explicit security assertions on non-method attributes.
+
+What Happens When You Make A Mistake Making 'SecurityInfo' Declarations?
+------------------------------------------------------------------------
+
+It's possible that you will make a mistake when making 'SecurityInfo'
+declarations.  For example, it is not legal to declare two
+conflicting permissions on a method::
+
+  class Foo(SimpleItem):
+      security = ClassSecurityInfo()
+
+      meta_type='Foo'
+
+      security.declareProtected('View foos', 'index_html')
+      def index_html(self):
+          """ make index_html web-publishable """
+          return "<html><body>hi!</body></html>"
+
+security.declareProtected('View', 'index_html')
+# whoops, declared a conflicting permission on index_html!
+
+When you make a mistake like this, the security machinery will
+accept the *first* declaration made in the code and will write
+an error to the Zope debug log upon encountering the second and
+following conflicting declarations during class initialization.
+It's similarly illegal to declare a method both private and
+public, or to declare a method both private and protected, or to
+declare a method both public and protected. A similar error will
+be raised in all of these cases.
+
+Note that Zope *will not* warn you if you misspell the name of
+a method in a declareProtected, declarePublic, or declarePrivate
+assertion.  For instance, you try to protect the 'index_html'
+method with the 'View' permission and make a mistake,
+spelling the name 'index_html' as 'inde_html', like so::
+
+  security.declareProtected('View', 'inde_html')
+  # whoops, declared a permission assertion for 'inde_html'
+  # when I really wanted it to be 'index_html'!
+  def index_html(self):
+      """ make index_html web-publishable """
+      return "<html><body>hi!</body></html>"
+
+You'll need to track down these kinds of problems yourself.
+
+Setting Default Roles For Permissions
+-------------------------------------
+
+When defining operations that are protected by permissions, one thing
+you commonly want to do is to arrange for certain roles to be
+associated with a particular permission *by default* for instances of
+your object.
+
+For example, say you are creating a *News Item* object. You want
+'Anonymous' users to have the ability to view news items by default;
+you don't want the site manager to have to explicitly change the
+security settings for each *News Item* just to give the 'Anonymous"
+role 'View' permission.
+
+What you want as a programmer is a way to specify that certain roles
+should have certain permissions by default on instances of your
+object, so that your objects have sensible and useful security
+settings at the time they are created. Site managers can always
+*change* those settings if they need to, but you can make life easier
+for the site manager by setting up defaults that cover the common
+case by default.
+
+As we saw earlier, the 'SecurityInfo' interface provided a way to
+associate methods with permissions. It also provides a way to
+associate a permission with a set of default roles that should have
+that permission on instances of your object.
+
+To associate a permission with one or more roles, use the following::
+
+  security.setPermissionDefault(permissionName, rolesList)
+
+The *permissionName* argument should be the name of a permission that
+you have used in your object and *rolesList* should be a sequence
+(tuple or list) of role names that should be associated with
+*permissionName* by default on instances of your object.
+
+Note that it is not always necessary to use this method. All
+permissions for which you did not set defaults using
+'setPermissionDefault' are assumed to have a single default role of
+'Manager'.  Notable exceptions to this rule include 'View' and
+'Access contents information', which always have the default roles
+'Manager' and 'Anonymous'.
+
+The 'setPermissionDefault' method of the 'SecurityInfo' object should
+be called only once for any given permission name.
+
+
+An Example of Associating Default Roles With Permissions
+--------------------------------------------------------
+
+Here is our 'Mailbox' example, updated to associate the 'View
+Mailbox' permission with the roles 'Manager' and 'Mailbox Owner' by
+default::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class Mailbox(ObjectManager):
+    """A mailbox object."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    # Set security for the object itself
+    security.declareObjectProtected('View Mailbox')
+
+    security.declareProtected('View management screens', 'manage')
+    manage=DTMLFile('mailbox_manage', globals())
+
+    security.declarePublic('messageCount')
+    def messageCount(self):
+      """Return a count of messages."""
+      return len(self._messages)
+
+    security.declareProtected('View Mailbox', 'listMessages')
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
+
+  # call this to initialize framework classes, which
+  # does the right thing with the security assertions.
+  Globals.InitializeClass(Mailbox)
+
+What Happens When You Make A Mistake Declaring Default Roles?
+-------------------------------------------------------------
+
+It's possible that you will make a mistake when making default roles
+declarations.  For example, it is not legal to declare two
+conflicting default roles for a permission::
+
+  class Foo(SimpleItem):
+      security = ClassSecurityInfo()
+
+      meta_type='Foo'
+
+      security.declareProtected('View foos', 'index_html')
+      def index_html(self):
+          """ """
+          return "<html><body>hi!</body></html>"
+
+      security.setPermissionDefault('View foos', ('Manager',))
+
+      security.setPermissionDefault('View foos', ('Anonymous',))
+      # whoops, conflicting permission defaults!
+
+When you make a mistake like this, the security machinery will accept
+the *first* declaration made in the code and will write an error to
+the Zope debug log about the second and following conflicting
+declarations upon class initialization.
+
+What Can (And Cannot) Be Protected By Class Security Info?
+----------------------------------------------------------
+
+It is important to note what can and cannot be protected using the
+'ClassSecurityInfo' interface. First, the security policy relies on
+*Acquisition* to aggregate access control information, so any class
+that needs to work in the security policy must have either
+'Acquisition.Implicit' or 'Acquisition.Explicit' in its base class
+hierarchy.
+
+The current security policy supports protection of methods and
+protection of subobjects that are instances. It does *not* currently
+support protection of simple attributes of basic Python types
+(strings, ints, lists, dictionaries). For instance::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  # We subclass ObjectManager, which has Acquisition in its
+  # base class hierarchy, so we can use SecurityInfo.
+
+  class MyClass(ObjectManager):
+    """example class"""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    # Set security for the object itself
+    security.declareObjectProtected('View')
+
+    # This is ok, because subObject is an instance
+    security.declareProtected('View management screens', 'subObject')
+    subObject=MySubObject()
+
+    # This is ok, because sayHello is a method
+    security.declarePublic('sayHello')
+    def sayHello(self):
+      """Return a greeting."""
+      return "hello!"
+
+    # This will not work, because foobar is not a method
+    # or an instance - it is a standard Python type
+    security.declarePublic('foobar')
+    foobar='some string'
+
+Keep this in mind when designing your classes. If you need simple
+attributes of your objects to be accessible (say via DTML), then you
+need to use the 'setDefaultAccess' method of 'SecurityInfo' in your
+class to allow this (see the note above about the security
+implications of this). In general, it is always best to expose the
+functionality of your objects through methods rather than exposing
+attributes directly.
+
+Note also that the actual 'ClassSecurityInfo' instance you use to
+make security assertions is implemented such that it is *never*
+accessible from restricted code or through the Web (no action on the
+part of the programmer is required to protect it).
+
+Inheritance And Class Security Declarations
+-------------------------------------------
+
+Python inheritance can prove confusing in the face of security
+declarations.
+
+If a base class which has already been run through "InitializeClass"
+is inherited by a superclass, nothing special needs to be done to
+protect the base class' methods within the superclass unless you wish
+to modify the declarations made in the base class.  The security
+declarations "filter down" into the superclass.
+
+On the other hand, if a base class hasn't been run through the global
+class initializer ('InitializeClass'), you need to proxy its security
+declarations in the superclass if you wish to access any of its
+methods within through-the-web code or via URL traversal.
+
+In other words, security declarations that you make using
+'ClassSecurityInfo' objects effect instances of the class upon which
+you make the declaration. You only need to make security declarations
+for the methods and subobjects that your class actually *defines*. If
+your class inherits from other classes, the methods of the base
+classes are protected by the security declarations made in the base
+classes themselves. The only time you would need to make a security
+declaration about an object defined by a base class is if you needed
+to *redefine* the security information in a base class for instances
+of your own class. An example below redefines a security assertion in
+a subclass::
+
+  from AccessControl import ClassSecurityInfo
+  import Globals
+
+  class MailboxBase(ObjectManager):
+    """A mailbox base class."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    security.declareProtected('View Mailbox', 'listMessages')
+    def listMessages(self):
+      """Return a sequence of message objects."""
+      return self._messages[:]
+
+    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
+
+  Globals.InitializeClass(MailboxBase)
+
+  class MyMailbox(MailboxBase):
+    """A mailbox subclass, where we want the security for 
+      listMessages to be public instead of protected (as 
+      defined in the base class)."""
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+
+    security.declarePublic('listMessages')
+
+  Globals.InitializeClass(MyMailbox)
+
+Class Security Assertions In Non-Product Code (External Methods/Python Scripts)
+-------------------------------------------------------------------------------
+
+Objects that are returned from Python Scripts or External Methods
+need to have assertions declared for themselves before they can be
+used in restricted code.  For example, assume you have an External
+Method that returns instances of a custom 'Book' class. If you want
+to call this External Method from DTML, and you'd like your DTML to
+be able to use the returned 'Book' instances, you will need to ensure
+that your class supports Acquisition, and you'll need to make
+security assertions on the 'Book' class and initialize it with the
+global class initializer (just as you would with a class defined in a
+Product). For example::
+
+  # an external method that returns Book instances
+
+  from AccessControl import ClassSecurityInfo
+  from Acquisition import Implicit
+  import Globals
+
+  class Book(Implicit):
+
+    def __init__(self, title):
+      self._title=title
+
+    # Create a SecurityInfo for this class
+    security = ClassSecurityInfo()
+    security.declareObjectPublic()
+
+    security.declarePublic('getTitle')
+    def getTitle(self):
+      return self._title
+
+  Globals.InitializeClass(Book)
+
+  # The actual external method
+  def GetBooks(self):
+    books=[]
+    books.append(Book('King Lear').__of__(self))
+    books.append(Book('Romeo and Juliet').__of__(self))
+    books.append(Book('The Tempest').__of__(self))
+    return books
+
+Note that we *wrap* the book instances by way of their __of__ methods
+to obtain a security context before returning them.
+
+Note that this particular example is slightly dangerous.  You need to
+be careful that classes defined in external methods not be made
+persistent, as this can cause Zope object database inconsistencies.
+In terms of this example, this would mean that you would need to be
+careful to not attach the Book object returned from the 'GetBook'
+method to a persistent object within the ZODB. See Chapter 4, "ZODB
+Persistent Components" for more information.  Thus it's generally a
+good idea to define the Book class in a Product if you want books to
+be persistent.  It's also less confusing to have all of your security
+declarations in Products.
+
+However, one benefit of the 'SecurityInfo' approach is that it is
+relatively easy to subclass and add security info to classes that you
+did not write. For example, in an External Method, you may want to
+return instances of 'Book' although 'Book' is defined in another
+module out of your direct control. You can still use 'SecurityInfo'
+to define security information for the class by using::
+
+  # an external method that returns Book instances
+
+  from AccessControl import ClassSecurityInfo
+  from Acquisition import Implicit
+  import bookstuff
+  import Globals
+
+  class Book(Implicit, bookstuff.Book):
+    security = ClassSecurityInfo()
+    security.declareObjectPublic()
+    security.declarePublic('getTitle')
+
+  Globals.InitializeClass(Book)
+
+  # The actual external method
+  def GetBooks(self):
+    books=[]
+    books.append(Book('King Lear'))
+    books.append(Book('Romeo and Juliet'))
+    books.append(Book('The Tempest'))
+    return books
+
+Module Security Assertions
+==========================
+
+Another kind of 'SecurityInfo' object you will use as a
+component developer is the 'ModuleSecurityInfo' object.
+
+'ModuleSecurityInfo' objects do for objects defined in modules
+what 'ClassSecurityInfo' objects do for methods defined in
+classes.  They allow module-level objects (generally functions) to
+be protected by security assertions.  This is most useful when
+attempting to allow through-the-web code to 'import' objects
+defined in a Python module.
+
+One major difference between 'ModuleSecurityInfo' objects and
+ClassSecurityInfo objects is that 'ModuleSecurityInfo' objects
+cannot be declared 'protected' by a permission.  Instead,
+ModuleSecurityInfo objects may only declare that an object is
+'public' or 'private'.  This is due to the fact that modules are
+essentially "placeless", global things, while permission
+protection depends heavily on "place" within Zope.
+
+Declaring Module Security
+-------------------------
+
+In order to use a filesystem Python module from restricted code such
+as Python Scripts, the module must have Zope security declarations
+associated with functions within it.  There are a number of ways to
+make these declarations:
+
+- By embedding the security declarations in the target module.  A
+  module that is written specifically for Zope may do so, whereas a
+  module not specifically written for Zope may not be able to do so.
+
+- By creating a wrapper module and embedding security declarations
+  within it.  In many cases it is difficult, impossible, or simply
+  undesirable to edit the target module.  If the number of objects in
+  the module that you want to protect or make public is small, you
+  may wish to simply create a wrapper module.  The wrapper module
+  imports objects from the wrapped module and provides security
+  declarations for them.
+
+- By placing security declarations in a filesystem Product.
+  Filesystem Python code, such as the '__init__.py' of a Product, can
+  make security declarations on behalf of an external module.  This
+  is also known as an "external" module security info declaration.
+
+The 'ModuleSecurityInfo' class is defined in the 'AccessControl'
+package of the Zope framework.
+
+Using ModuleSecurityInfo Objects
+--------------------------------
+
+  Instances of 'ModuleSecurityInfo' are used in two different
+  situations.  In embedded declarations, inside the module they
+  affect.  And in external declarations, made on behalf of a
+  module which may never be imported.
+
+Embedded ModuleSecurityInfo Declarations
+----------------------------------------
+
+An embedded ModuleSecurityInfo declaration causes an object in its
+module to be importable by through-the-web code.
+
+Here's an example of an embedded declaration::
+
+  from AccessControl import ModuleSecurityInfo
+  modulesecurity = ModuleSecurityInfo()
+  modulesecurity.declarePublic('foo')
+
+  def foo():
+      return "hello"
+      # foo
+
+  modulesecurity.apply(globals())
+
+When making embedded ModuleSecurityInfo declarations, you should
+instantiate a ModuleSecurityInfo object and assign it to a name.
+It's wise to use the recommended name 'modulesecurity' for
+consistency's sake.  You may then use the modulesecurity object's
+'declarePublic' method to declare functions inside of the current
+module as public.  Finally, appending the last line
+("modulesecurity.apply(globals())") is an important step.  It's
+necessary in order to poke the security machinery into action.  The
+above example declares the 'foo' function public.
+
+The name 'modulesecurity' is used for consistency and for the benefit
+of new component authors, who often learn from looking at other
+people's code.  You do not have to use the name 'modulesecurity' for
+the security infrastructure to recognize your assertion information,
+but it is recommended as a convention.
+
+External ModuleSecurityInfo Declarations
+----------------------------------------
+
+By creating a ModuleSecurityInfo instance with a module name
+argument, you can make declarations on behalf of a module without
+having to edit or import the module.
+
+Here's an example of an external declaration::
+
+   from AccessControl import ModuleSecurityInfo
+   # protect the 'foo' function within (yet-to-be-imported) 'foomodule'
+   ModuleSecurityInfo('foomodule').declarePublic('foo')
+
+This declaration will cause the following code to work within
+PythonScripts::
+
+   from foomodule import foo
+
+When making external ModuleSecurityInfo declarations, you needn't use
+the "modulesecurity.apply(globals())" idiom demonstrated in the
+embedded declaration section above.  As a result, you needn't assign
+the ModuleSecurityInfo object to the name 'modulesecurity'.
+
+Providing Access To A Module Contained In A Package
+---------------------------------------------------
+
+Note that if you want to provide access to a module inside of a
+package which lives in your PYTHONPATH, you'll need to provide
+security declarations for *all of the the packages and sub-packages
+along the path used to access the module.*
+
+For example, assume you have a function foo, which lives inside a
+module named 'module', which lives inside a package named 'package2',
+which lives inside a package named 'package1' You might declare the
+'foo' function public via this chain of declarations::
+
+  ModuleSecurityInfo('package1').declarePublic('package2')
+  ModuleSecurityInfo('package1.package2').declarePublic('module')
+  ModuleSecurityInfo('package1.package2.module').declarePublic('foo')
+
+Note that in the code above we took the following steps:
+
+- make a ModuleSecurityInfo object for 'package1'
+
+- call the declarePublic method of the 'package1'
+  ModuleSecurityInfo object, specifying 'package2' as what
+  we're declaring public.  This allows through the web code to
+  "see" package2 inside package1.
+
+- make a ModuleSecurityInfo object for 'package1.package2'.
+
+- call the declarePublic method of the 'package1.package2'
+  ModuleSecurityInfo object, specifying 'module' as what we're
+  declaring public.  This allows through the web code to "see"
+  'package1.package2.module'.
+
+- declare 'foo' public inside the ModuleSecurityInfo for
+  'package1.package2.module'. 
+
+Through-the-web code may now perform an import ala: 'import
+package1.package2.module.foo'
+
+Beware that Zope is buggy from 2.3 to 2.5.0b3.  If you make module
+security declarations in more than one Product, only one of the
+Products' security assertions will actually take effect.  This is
+repaired in Zope 2.5.0 and beyond.
+
+Many people who use Zope will be concerned with using
+ModuleSecurityInfo to make declarations on modules which live within
+Zope's Products directory.  This is just an example of declaring
+module security on a module within a package.  Here is an example of
+using ModuleSecurityInfo to make security declarations on behalf of
+the 'CatalogError' class in the 'ZCatalog.py' module.  This could be
+placed, for instance, within the any Product's '__init__.py' module::
+
+  from AccessControl import ModuleSecurityInfo
+  ModuleSecurityInfo('Products').declarePublic('Catalog')
+  ModuleSecurityInfo('Products.Catalog').declarePublic('CatalogError')
+
+Declaring Module Security On Modules Implemented In C
+-----------------------------------------------------
+
+Certain modules, such as the standard Python 'sha' module, provide
+extension types instead of classes, as the 'sha' module is
+implemented in C. Security declarations typically cannot be added to
+extension types, so the only way to use this sort of module is to
+write a Python wrapper class, or use External Methods.
+
+Default Module Security Info Declarations
+-----------------------------------------
+
+Through-the-web Python Scripts are by default able to import a small
+number of Python modules for which there are security
+declarations. These include 'string', 'math', and 'random'. The only
+way to make other Python modules available for import is to add
+security declarations to them in the filesystem.
+
+Utility Functions For Allowing Import of Modules By Through The Web Code
+------------------------------------------------------------------------
+
+Instead of manually providing security declarations for each function
+in a module, the utility function "allow_class" and "allow_module"
+have been created to help you declare the entire contents of a class
+or module as public.
+
+You can handle a module, such as base64, that contains only safe
+functions by writing 'allow_module("module_name")'.  For instance::
+
+  from Products.PythonScripts.Utility import allow_module
+  allow_module("base64")
+
+This statement declares all functions in the 'base64' module (
+'encode', 'decode', 'encodestring', and 'decodestring' ) as public,
+and from a script you will now be able to perform an import statement
+such as "from base64 import encodestring".
+
+
+To allow access to only some names in a module, you can eschew the
+allow_class and allow_module functions for the lessons you learned in
+the previous section and do the protection "manually"::
+
+  from AccessControl import ModuleSecurityInfo
+  ModuleSecurityInfo('module_name').declarePublic('name1','name2', ...)
+
+Making Permission Assertions On A Constructor
+---------------------------------------------
+
+When you develop a Python disk-based product, you will generally be
+required to make "constructor" methods for the objects which you wish
+to make accessible via the Zope management interface by users of your
+Product.  These constructors are usually defined within the modules
+which contain classes which are intended to be turned into Zope
+instances.  For more information on how constructors are used in Zope
+with security, see Chapter 3 "Zope Products".
+
+The Zope Product machinery "bootstraps" Product-based classes with
+proper constructors into the namespace of the Zope management
+interface "Add" list at Zope startup time.  This is done as a
+consequence of registering a class by way of the Product's
+'__init__.py' 'intialize' function.  If you want to make, for
+example, the imaginary 'FooClass' in your Product available from the
+"Add" list, you may construct an '__init__.py' file that looks much
+like this::
+
+      from FooProduct import FooClass
+
+      def initialize(context):
+          """ Initialize classes in the FooProduct module """
+          context.registerClass(
+              FooProduct.FooClass, # the class object
+              permission='Add FooClasses',
+              constructors=(FooProduct.manage_addFooClassForm,
+                            FooProduct.manage_addFooClass),
+              icon='foo.gif'
+              )
+
+The line of primary concern to us above is the one which says
+"permission='Add FooClasses'".  This is a permission declaration
+which, thanks to Zope product initialization, restricts the adding of
+FooClasses to those users who have the 'Add FooClasses' permission by
+way of a role association determined by the system administrator.
+
+If you do not include a 'permission' argument to 'registerClass',
+then Zope will create a default permission named 'Add [meta-type]s'.
+So, for example, if your object had a meta_type of 'Animal', then
+Zope would create a default permission, 'Add Animals'.  For the most
+part, it is much better to be explicit then to rely on Zope to take
+care of security details for you, so be sure to specify a permission
+for your object.
+
+Designing For Security
+======================
+
+"Security is hard." -- Jim Fulton.
+
+When you're under a deadline, and you "just want it to work", dealing
+with security can be difficult.  As a component developer, following
+these basic guidelines will go a long way toward avoiding problems
+with security integration. They also make a good debugging checklist!
+
+- Ensure that any class that needs to work with security has
+  'Acquisition.Implicit' or 'Acquisition.Explicit' somewhere in its
+  base class hierarchy.
+
+- Design the interface to your objects around methods; don't expect
+  clients to access instance attributes directly.
+
+- Ensure that all methods meant for use by restricted code have been
+  protected with appropriate security assertions.
+
+- Ensure that you called the global class initializer on all classes
+  that need to work with security.
+
+Compatibility
+=============
+
+The implementation of the security assertions and 'SecurityInfo'
+interfaces described in this document are available in Zope 2.3 and
+higher.
+
+Older Zope Products do not use the 'SecurityInfo' interfaces for
+security assertions, because these interfaces didn't exist at the
+time.  These Zope products will continue to work without modification
+until further notice.
+
+Using The RoleManager Base Class With Your Zope Product
+=======================================================
+
+After your Product is deployed, system managers and other users of
+your Product often must deal with security settings on instances they
+make from your classes.
+
+Product classes which inherit Zope's standard RoleManager base class
+allow instances of the class to present a security interface.  This
+security interface allows managers and developers of a site to
+control an instance's security settings via the Zope management
+interface.
+
+The user interface is exposed via the *Security* management view.
+From this view, a system administrator may secure instances of your
+Product's class by associating roles with permissions and by
+asserting that your object instance contains "local roles".  It also
+allows them to create "user-defined roles" within the Zope management
+framework in order to associate these roles with the permissions of
+your product and with users.  This user interface and its usage
+patterns are explained in more detail within the Zope Book's security
+chapter.
+
+If your Product's class does not inherit from 'RoleManager', its
+methods will still retain the security assertions associated with
+them, but you will be unable to allow users to associate roles with
+the permissions you've defined respective to instances of your class.
+Your objects will also not allow local role definitions.  Note that
+objects which inherit from the 'SimpleItem.SimpleItem' mixin class
+already inherit from 'RoleManager'.
+
+Conclusion
+==========
+
+Zope security is based upon roles and permissions. Users have
+roles. Security policies map permissions to roles. Classes protect
+methods with permissions. As a developer you main job is to protect
+your classes by associating methods with permissions. Of course there
+are many other details such as protecting modules and functions,
+creating security user interfaces, and initializing security
+settings.

Copied: zope2docs/branches/baijum-reorganize/zdgbook/TestingAndDebugging.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/TestingAndDebugging.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/TestingAndDebugging.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/TestingAndDebugging.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,800 @@
+#####################
+Testing and Debugging
+#####################
+
+As you develop Zope applications you may run into problems.  This
+chapter covers debugging and testing techniques that can help you.
+The Zope debugger allow you to peek inside a running process and find
+exactly what is going wrong.  Unit testing allows you to automate the
+testing process to ensure that your code still works correctly as you
+change it.  Finally, Zope provides logging facilities which allow you
+to emit warnings and error messages.
+
+
+Debugging
+=========
+
+Zope provides debugging information through a number of sources.  It
+also allows you a couple avenues for getting information about Zope
+as it runs.
+
+The Control Panel
+-----------------
+
+The control panel provides a number of views that can help you debug
+Zope, especially in the area of performance.  The *Debugging
+Information* link on the control panel provides two views, *Debugging
+Info* and *Profiling*.
+
+Debugging info provides information on the number of object
+references and the status of open requests.  The object references
+list displays the name of the object and the number of references to
+that object in Zope.  Understanding how reference counts help
+debugging is a lengthy subject, but in general you can spot memory
+leaks in your application if the number of references to certain
+objects increases without bound.  The busier your site is, or the
+more content it holds, the more reference counts you will tend to
+have.
+
+Profiling uses the standard Python profiler.  This is turned on by
+setting the 'PROFILE_PUBLISHER' environment variable before executing
+Zope.
+
+When the profiler is running, the performance of your Zope system
+will suffer a lot.  Profiling should only be used for short periods
+of time, or on a separate ZEO client so that your normal users to not
+experience this significant penalty.
+
+Profiling provides you with information about which methods in your
+Zope system are taking the most time to execute.  It builds a
+*profile*, which lists the busiest methods on your system, sorted by
+increasing resource usage.  For details on the meaning of the
+profiler's output, read the `standard Python documentation
+<http://www.python.org/doc/current/lib/profile.html>`_
+
+Product Refresh Settings
+------------------------
+
+As of Zope 2.4 there is a *Refresh* view on all Control Panel
+Products.  Refresh allows you to reload your product's modules as you
+change them, rather than having to restart Zope to see your changes.
+The *Refresh* view provides the same debugging functionality
+previously provided by Shane Hathaway's Refresh Product.
+
+To turn on product refresh capabilities place a 'refresh.txt' file in
+your product's directory.  Then visit the *Refresh* view of your
+product in the management interface.  Here you can manually reload
+your product's modules with the *Refresh this product* button.  This
+allows you to immediately see the effect of your changes, without
+restarting Zope.  You can also turn on automatic refreshing which
+causes Zope to frequently check for changes to your modules and
+refresh your product when it detects that your files have changed.
+Since automatic refresh causes Zope to run more slowly, it is a good
+idea to only turn it on for a few products at a time.
+
+Debug Mode
+----------
+
+Setting the 'Z_DEBUG_MODE=1' environment puts Zope into debug mode.
+This mode reduces the performance of Zope a little bit.  Debug model
+has a number of wide ranging effects:
+
+- Tracebacks are shown on the browser when errors are raised.
+
+- External Methods and DTMLFile objects are checked to see if they
+  have been modified every time they are called.  If modified, they
+  are reloaded.
+
+- Zope will not fork into the background in debug mode, instead, it
+  will remain attached to the terminal that started it and the main
+  logging information will be redirected to that terminal.
+
+Normally, debug mode is set using the '-D' switch when starting Zope,
+though you can set the environment variable directly if you wish.
+
+By using debug mode and product refresh together you will have little
+reason to restart Zope while developing.
+
+The Python Debugger
+-------------------
+
+Zope is integrated with the Python debugger (pdb).  The Python
+debugger is pretty simple as command line debuggers go, and anyone
+familiar with other popular command line debuggers (like gdb) will
+feel right at home in pdb.
+
+For an introduction to pdb see the standard `pdb documentation
+<http://www.python.org/doc/current/lib/module-pdb.html>`_ .
+
+There are a number of ways to debug a Zope process:
+
+  o You can shut down the Zope server and simulate a request on the
+    command line.
+
+  o You can run a special ZEO client that debugs a running server.
+
+  o You can run Zope in debug model and enter the debugger
+    through Zope's terminal session.
+
+The first method is an easy way to debug Zope if you are not running
+ZEO.  First, you must first shut down the Zope process.  It is not
+possible to debug Zope in this way and run it at the same time.
+Starting up the debugger this way will by default start Zope in
+single threaded mode.
+
+For most Zope developer's purposes, the debugger is needed to debug
+some sort of application level programming error.  A common scenario
+is when developing a new product for Zope.  Products extend Zope's
+functionality but they also present the same kind of debugging
+problems that are commonly found in any programming environment.  It
+is useful to have an existing debugging infrastructure to help you
+jump immediately to your new object and debug it and play with it
+directly in pdb.  The Zope debugger lets you do this.
+
+In reality, the "Zope" part of the Zope debugger is actually just a
+handy way to start up Zope with some pre-configured break points and
+to tell the Python debugger where in Zope you want to start
+debugging.
+
+Simulating HTTP Requests
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now for an example. Remember, for this example to work, you *must*
+shut down Zope.  Go to your Zope's 'lib/python' directory and fire up
+Python and import 'Zope' and 'ZPublisher'::
+
+  $ cd lib/python
+  $ python
+  Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
+  Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
+  >>> import Zope, ZPublisher
+  >>>
+
+Here you have run the Python interpreter (which is where using the
+debugger takes place) and imported two modules, 'Zope' and
+'ZPublisher'.  If Python complains about an 'ImportError' and not
+being able to find either module, then you are probably in the wrong
+directory, or you have not compiled Zope properly.  If you get this
+message::
+
+  ZODB.POSException.StorageSystemError: Could not lock the database
+  file.  There must be another process that has opened the file.
+
+This tells you that Zope is currently running.  Shutdown Zope and try
+again.
+
+The 'Zope' module is the main Zope application module.  When you
+import 'Zope' it sets up Zope.  'ZPublisher' is the Zope ORB.  See
+Chapter 2 for more information about 'ZPublisher'.
+
+You can use the 'ZPublisher.Zope' function to simulate an HTTP
+request.  Pass the function a URL relative the your root Zope object.
+Here is an example of how to simulate an HTTP request from the
+debugger::
+
+  >>> ZPublisher.Zope('')
+  Status: 200 OK
+  X-Powered-By: Zope (www.zope.org), Python (www.python.org)
+  Content-Length: 1238
+  Content-Type: text/html
+
+  <HTML><HEAD><TITLE>Zope</TITLE>
+
+    ... blah blah...
+
+  </BODY></HTML>
+  >>> 
+
+If you look closely, you will see that the content returned is
+*exactly* what is returned when you call your root level object
+through HTTP, including all the HTTP headers.
+
+Keep in mind that calling Zope this way does NOT involve a web
+server.  No ports are opened, the 'ZServer' code is not even
+imported.  In fact, this is just an interpreter front end to the same
+application code the ZServer *does* call.
+
+Interactive Debugging
+~~~~~~~~~~~~~~~~~~~~~
+
+Debugging involves publishing a request up to a point where you think
+it's failing, and then inspecting the state of your variables and
+objects.  The easy part is the actual inspection, the hard part is
+getting your program to stop at the right point.
+
+So, for the sake our example, let's say that you have a 'News' object
+which is defined in a Zope Product called 'ZopeNews', and is located
+in the 'lib/python/Products/ZopeNews' directory.  The class that
+defines the 'News' instance is also called 'News', and is defined in
+the 'News.py' module in your product.
+
+Therefore, from Zope's perspective the fully qualified name of your
+class is 'Products.ZopeNews.News.News'.  All Zope objects have this
+kind of fully qualified name.  For example, the 'ZCatalog' class can
+be found in 'Products.ZCatalog.ZCatalog.ZCatalog' (The redundancy is
+because the product, module, and class are all named 'ZCatalog').
+
+Now let's create an example method to debug.  You want your news
+object to have a 'postnews' method, that posts news::
+
+  class News(...):
+
+      ...
+
+      def postnews(self, news, author="Anonymous"):
+          self.news = news
+
+      def quote(self):
+          return '%s said, "%s"' % (self.author, self.news)
+
+You may notice that there's something wrong with the 'postnews'
+method.  The method assigns 'news' to an instance variable, but it
+does nothing with 'author'.  If the 'quote' method is called, it will
+raise an 'AttributeError' when it tries to look up the name
+'self.author'.  Although this is a pretty obvious goof, we'll use it
+to illustrate using the debugger to fix it.
+
+Running the debugger is done in a very similar way to how you called
+Zope through the python interpreter before, except that you introduce
+one new argument to the call to 'Zope'::
+
+  >>> ZPublisher.Zope('/News/postnews?new=blah', d=1)
+  * Type "s<cr>c<cr>" to jump to beginning of real publishing process.
+  * Then type c<cr> to jump to the beginning of the URL traversal
+    algorithm.
+  * Then type c<cr> to jump to published object call.
+  > <string>(0)?()
+  pdb> 
+
+Here, you call Zope from the interpreter, just like before, but there
+are two differences.  First, you call the 'postnews' method with an
+argument using the URL, '/News/postnews?new=blah'.  Second, you
+provided a new argument to the Zope call, 'd=1'.  The 'd' argument,
+when true, causes Zope to fire up in the Python debugger, pdb.
+Notice how the Python prompt changed from '>>>' to 'pdb>'.  This
+indicates that you are in the debugger.
+
+When you first fire up the debugger, Zope gives you a helpful message
+that tells you how to get to your object.  To understand this
+message, it's useful to know how you have set Zope up to be debugged.
+When Zope fires up in debugger mode, there are three breakpoints set
+for you automatically (if you don't know what a breakpoint is, you
+need to read the python `debugger documentation
+<http://www.python.org/doc/current/lib/module-pdb.html>`_).
+
+The first breakpoint stops the program at the point that ZPublisher
+(the Zope ORB) tries to publish the application module (in this case,
+the application module is 'Zope').  The second breakpoint stops the
+program right before ZPublisher tries to traverse down the provided
+URL path (in this case, '/News/postnews').  The third breakpoint will
+stop the program right before ZPublisher calls the object it finds
+that matches the URL path (in this case, the 'News' object).
+
+So, the little blurb that comes up and tells you some keys to press
+is telling you these things in a terse way.  Hitting 's' will *step*
+you into the debugger, and hitting 'c' will *continue* the execution
+of the program until it hits a breakpoint.
+
+Note however that none of these breakpoints will stop the program at
+'postnews'.  To stop the debugger right there, you need to tell the
+debugger to set a new breakpoint.  Why a new breakpoint?  Because
+Zope will stop you before it traverse your objects path, it will stop
+you before it calls the object, but if you want to stop it *exactly*
+at some point in your code, then you have to be explicit.  Sometimes
+the first three breakpoints are convienent, but often you need to set
+your own special break point to get you exactly where you want to go.
+
+Setting a breakpoint is easy (and see the next section for an even
+easier method).  For example::
+
+  pdb> import Products
+  pdb> b Products.ZopeNews.News.News.postnews
+  Breakpoint 5 at C:\Program Files\WebSite\lib\python\Products\ZopeNews\News.py:42
+  pdb> 
+
+First, you import 'Products'.  Since your module is a Zope product,
+it can be found in the 'Products' package.  Next, you set a new
+breakpoint with the *break* debugger command (pdb allows you to use
+single letter commands, but you could have also used the entire word
+'break').  The breakpoint you set is
+'Products.ZopeNews.News.News.postnews'.  After setting this
+breakpoint, the debugger will respond that it found the method in
+question in a certain file, on a certain line (in this case, the
+fictitious line 42) and return you to the debugger.
+
+Now, you want to get to your 'postnews' method so you can start
+debugging it.  But along the way, you must first *continue* through
+the various breakpoints that Zope has set for you.  Although this may
+seem like a bit of a burden, it's actually quite good to get a feel
+for how Zope works internally by getting down the rhythm that Zope
+uses to publish your object.  In these next examples, my comments
+will begin with '#".  Obviously, you won't see these comments when
+you are debugging.  So let's debug::
+
+  pdb> s
+  # 's'tep into the actual debugging
+
+  > <string>(1)?()
+  # this is pdb's response to being stepped into, ignore it
+
+  pdb> c
+  # now, let's 'c'ontinue onto the next breakpoint
+
+  > C:\Program Files\WebSite\lib\python\ZPublisher\Publish.py(112)publish()
+  -> def publish(request, module_name, after_list, debug=0,
+
+  # pdb has stopped at the first breakpoint, which is the point where
+  # ZPubisher tries to publish the application module.
+
+  pdb> c
+  # continuing onto the next breakpoint you get...
+
+  > C:\Program Files\WebSite\lib\python\ZPublisher\Publish.py(101)call_object()
+  -> def call_object(object, args, request):
+
+Here, 'ZPublisher' (which is now publishing the application) has
+found your object and is about to call it.  Calling your object
+consists of applying the arguments supplied by 'ZPublisher' to the
+object.  Here, you can see how 'ZPublisher' is passing three
+arguments into this process.  The first argument is 'object' and is
+the actual object you want to call.  This can be verified by
+*printing* the object::
+
+  pdb> p object
+  <News instance at 00AFE410>
+
+Now you can inspect your object (with the *print* command) and even
+play with it a bit.  The next argument is 'args'.  This is a tuple of
+arguments that 'ZPublisher' will apply to your object call.  The
+final argument is 'request'.  This is the request object and will
+eventually be transformed in to the DTML usable object 'REQUEST'. Now
+continue, your breakpoint is next::
+
+  pdb> c    
+  > C:\Program Files\WebSite\lib\python\Products\ZopeNews\News.py(42)postnews()
+  -> def postnews(self, N)
+
+Now you are here, at your method.  To be sure, tell the debugger to
+show you where you are in the code with the 'l' command.  Now you can
+examine variable and perform all the debugging tasks that the Python
+debugger provides.  From here, with a little knowledge of the Python
+debugger, you should be able to do any kind of debugging task that is
+needed.
+
+Interactive Debugging Triggered From the Web
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you are running in debug mode you can set break points in your
+code and then jump straight to the debugger when Zope comes across
+your break points.  Here's how to set a breakpoint::
+
+  import pdb;pdb.set_trace()
+
+Now start Zope in debug mode and point your web browser at a URL that
+causes Zope to execute the method that includes a breakpoint.  When
+this code is executed, the Python debugger will come up in the
+terminal where you started Zope.  Also note that from your web
+browser it looks like Zope is frozen.  Really it's just waiting for
+you do your debugging.
+
+From the terminal you are inside the debugger as it is executing your
+request.  Be aware that you are just debugging one thread in Zope,
+and other requests may be being served by other threads.  If you go
+to the *Debugging Info* screen while in the debugger, you can see
+your debugging request and how long it has been open.
+
+It is often more convenient to use this method to enter the debugger
+than it is to call 'ZPublisher.Zope' as detailed in the last section.
+
+Post-Mortem Debugging
+~~~~~~~~~~~~~~~~~~~~~
+
+Often, you need to use the debugger to chase down obscure problems in
+your code, but sometimes, the problem is obvious, because an
+exception gets raised.  For example, consider the following method on
+your 'News' class::
+
+  def quote(self):
+      return '%s said, "%s"' % (self.Author, self.news)
+
+Here, you can see that the method tries to substitute 'self.Author'
+in a string, but earlier we saw that this should really be
+'self.author'.  If you tried to run this method from the command
+line, an exception would be raised::
+
+  >>> ZPublisher.Zope('/News/quote')
+  Traceback (most recent call last):
+    File "<stdin>", line 1, in ?
+    File "./News.py", line 4, in test
+      test2()
+    File "./News.py", line 3, in test2
+      return '%s said, "%s"' % (self.Author, self.news)
+  NameError: Author
+  >>>
+
+Using Zope's normal debugging methods, you would typically need to
+start from the "beginning" and step your way down through the
+debugger to find this error (in this case, the error is pretty
+obvious, but more often than not errors can be pretty obscure!).
+
+Post-mortem debugging allows you to jump *directly* to the spot in
+your code that raised the exception, so you do not need to go through
+the possibly tedious task of stepping your way through a sea of
+Python code.  In the case of our example, you can just pass
+'ZPublisher.Zope' call a 'pm' argument that is set to 1::
+
+          >>> ZPublisher.Zope('/News/quote', pm=1)
+          Traceback (most recent call last):
+            File "<stdin>", line 1, in ?
+            File "./News.py", line 4, in test
+              test2()
+            File "./News.py", line 3, in test2
+              return '%s said, "%s"' % (self.Author, self.news)
+          NameError: Author
+          (pdb)
+
+Here, you can see that instead of taking you back to a python prompt,
+the post mortem debugging flag has caused you to go right into the
+debugging, *exactly* at the point in your code where the exception is
+raised.  This can be verified with the debugger's (l)ist
+command. Post mortem debugging offers you a handy way to jump right
+to the section of your code that is failing in some obvious way by
+raising an exception.
+
+Debugging With ZEO
+~~~~~~~~~~~~~~~~~~
+
+ZEO presents some interesting debugging abilities.  ZEO lets you
+debug one ZEO client when other clients continue to server requests
+for your site.  In the above examples, you have to shut down Zope to
+run in the debugger, but with ZEO, you can debug a production site
+while other clients continue to serve requests. Using ZEO is beyond
+the scope of this chapter. However, once you have ZEO running, you
+can debug a client process exactly as you debug a single-process
+Zope.
+
+
+Unit Testing
+============
+
+Unit testing allows you to automatically test your classes to make
+sure they are working correctly. By using unit tests you can make
+sure as you develop and change your classes that you are not breaking
+them. Zope comes with Pyunit. You can find out more information on
+Pyunit at `the Pyunit home page <http://pyunit.sourceforge.net/>`_
+. Pyunit is also part of the Python `standard library
+<http://www.python.org/doc/lib/module-unittest.html>`_ as of Python
+2.1.
+
+
+What Are Unit Tests
+-------------------
+
+A "unit" may be defined as a piece of code with a single intended
+purpose.  A "unit test" is defined as a piece of code which exists
+to codify the intended behavior of a unit and to compare its
+intended behavior against its actual behavior.
+
+Unit tests are a way for developers and quality assurance engineers
+to quickly ascertain whether independent units of code are working as
+expected.  Unit tests are generally written at the same time as the
+code they are intended to test.  A unit testing framework allows a
+collection of unit tests to be run without human intervention,
+producing a minimum of output if all the tests in the collection are
+successful.
+
+It's a good idea to have a sense of the limits of unit testing.  From
+the `Extreme Programming Enthusiast website
+<http://c2.com/cgi/wiki?UnitTestsDefined>`_ here is a list of things
+that unit tests are *not*:
+
+- Manually operated.
+
+- Automated screen-driver tests that simulate user input (these are
+  "functional tests").
+
+- Interactive.  They run "no questions asked."
+
+- Coupled.  They run without dependencies except those native to the
+  thing being tested.
+
+- Complicated.  Unit test code is typically straightforward
+  procedural code that simulates an event.
+
+Writing Unit Tests
+------------------
+
+Here are the times when you should write unit tests:
+
+* When you write new code
+
+* When you change and enhance existing code
+
+* When you fix bugs
+
+It's much better to write tests when you're working on code than to
+wait until you're all done and then write tests.
+
+You should write tests that exercise discrete "units" of
+functionality.  In other words, write simple, specific tests that
+test one capability.  A good place to start is with interfaces and
+classes.  Classes and especially interfaces already define units of
+work which you may wish to test.
+
+Since you can't possibly write tests for every single capability and
+special case, you should focus on testing the riskiest parts of your
+code.  The riskiest parts are those that would be the most disastrous
+if they failed.  You may also want to test particularly tricky or
+frequently changed things.
+
+Here's an example test script that tests the 'News' class defined
+earlier in this chapter::
+
+  import unittest
+  import News
+
+  class NewsTest(unittest.TestCase):
+
+      def testPost(self):
+          n=News()
+          s='example news'
+          n.postnews(s)
+          assert n.news==s
+
+      def testQuote(self):
+          n=News()
+          s='example news'
+          n.postnews(s)
+          assert n.quote()=='Anonymous said: "%s"' % s
+          a='Author'
+          n.postnews(s, a)
+          assert n.quote()=='%s said: "%s"' % (a, s)
+
+  def test_suite():
+     return unittest.makeSuite(NewsTest, 'news test')
+
+  def main():
+     unittest.TextTestRunner().run(test_suite())
+
+  if __name__=="__main__":
+      main()
+
+You should save tests inside a 'tests' sub-directory in your
+product's directory. Test scripts file names should start with test,
+for example 'testNews.py'. You may accumulate many test scripts in
+your product's 'tests' directory.  You can run test your product by
+running the test scripts.
+
+We cannot cover all there is to say about unit testing here. Take a
+look at the Pyunit `documentation
+<http://pyunit.sourceforge.net/pyunit.html>`_ for more background on
+unit testing.
+
+Zope Test Fixtures
+------------------
+
+One issue that you'll run into when unit testing is that you may need
+to set up a Zope environment in order to test your products.  You can
+solve this problem in two ways.  First, you can structure your
+product so that much of it can be tested without Zope (as you did in
+the last section).  Second, you can create a test fixture that sets
+up a Zope environment for testing.
+
+To create a test fixture for Zope you'll need to:
+
+1. Add Zope's 'lib/python' directory to the Python path.
+
+2. Import 'Zope' and any other needed Zope modules and packages.
+
+3. Get a Zope application object.
+
+4. Do your test using the application object.
+
+5. Clean up the test by aborting or committing the transaction and
+   closing the Zope database connection.
+
+Here's an example Zope test fixture that demonstrates how to do each
+of these steps::
+
+  import os, os.path, sys, string
+  try:
+      import unittest
+  except ImportError:
+      fix_path()
+      import unittest
+
+  class MyTest(unittest.TestCase):
+
+      def setUp(self):
+          # Get the Zope application object and store it in an
+          # instance variable for use by test methods
+          import Zope
+          self.app=Zope.app()
+
+      def tearDown(self):
+          # Abort the transaction and shut down the Zope database
+          # connection.
+          get_transaction().abort()
+          self.app._p_jar.close()
+
+      # At this point your test methods can perform tests using
+      # self.app which refers to the Zope application object.
+
+      ...
+
+  def fix_path():
+      # Add Zope's lib/python directory to the Python path
+      file=os.path.join(os.getcwd(), sys.argv[0])
+      dir=os.path.join('lib', 'python')
+      i=string.find(file, dir)
+      sys.path.insert(0, file[:i+len(dir)])
+
+  def test_suite():
+     return unittest.makeSuite(MyTest, 'my test')
+
+  def main():
+     unittest.TextTestRunner().run(test_suite())
+
+  if __name__=="__main__":
+      fix_path()
+      main()
+
+This example shows a fairly complete Zope test fixture.  If your Zope
+tests only needs to import Zope modules and packages you can skip
+getting a Zope application object and closing the database
+transaction.
+
+Some times you may run into trouble if your test assuming that there
+is a current Zope request.  There are two ways to deal with this.
+One is to use the 'makerequest' utility module to create a fake
+request.  For example::
+
+  class MyTest(unittest.TestCase):
+      ...
+
+      def setup(self):
+          import Zope
+          from Testing import makerequest
+          self.app=makerequest.makerequest(Zope.app())
+
+This will create a Zope application object that is wrapped in a
+request.  This will enable code that expects to acquire a 'REQUEST'
+attribute work correctly.
+
+Another solution to testing methods that expect a request is to use
+the 'ZPublisher.Zope' function described earlier.  Using this
+approach you can simulate HTTP requests in your unit tests.  For
+example::
+
+  import ZPublisher
+
+  class MyTest(unittest.TestCase):
+      ...
+
+      def testWebRequest(self):
+          ZPublisher.Zope('/a/url/representing/a/method?with=a&couple=arguments',
+                          u='username:password', 
+                          s=1, 
+                          e={'some':'environment', 'variable':'settings'})
+
+If the 's' argument is passed to 'ZPublisher.Zope' then no output
+will be sent to 'sys.stdout'.  If you want to capture the output of
+the publishing request and compare it to an expected value you'll
+need to do something like this::
+
+  f=StringIO()
+  temp=sys.stdout
+  sys.stdout=f
+  ZPublisher.Zope('/myobject/mymethod')
+  sys.stdout=temp
+  assert f.getvalue() == expected_output
+
+Here's a final note on unit testing with a Zope test fixture: you may
+find Zope helpful.  ZEO allows you to test an application while it
+continues to serve other users.  It also speeds Zope start up time
+which can be a big relief if you start and stop Zope frequently while
+testing.
+
+Despite all the attention we've paid to Zope testing fixtures, you
+should probably concentrate on unit tests that don't require a Zope
+test fixture.  If you can't test much without Zope there is a good
+chance that your product would benefit from some refactoring to make
+it simpler and less dependent on the Zope framework.
+
+Logging
+=======
+
+Zope provides a framework for logging information to Zope's
+application log.  You can configure Zope to write the application log
+to a file, syslog, or other back-end.
+
+The logging API defined in the 'zLOG' module.  This module provides
+the 'LOG' function which takes the following required arguments:
+
+- subsystem -- The subsystem generating the message (e.g. "ZODB")
+
+- severity -- The "severity" of the event.  This may be an integer or
+  a floating point number.  Logging back ends may consider the int()
+  of this value to be significant.  For example, a back-end may
+  consider any severity whose integer value is WARNING to be a
+  warning.
+
+- summary -- A short summary of the event
+
+These arguments to the 'LOG' function are optional:
+
+- detail -- A detailed description
+
+- error -- A three-element tuple consisting of an error type, value,
+  and traceback.  If provided, then a summary of the error is added
+  to the detail.
+
+- reraise -- If provided with a true value, then the error given by
+  error is reraised.
+
+You can use the 'LOG' function to send warning and errors to the Zope
+application log.
+
+Here's an example of how to use the 'LOG' function to write debugging
+messages::
+
+  from zLOG import LOG, DEBUG
+  LOG('my app', DEBUG, 'a debugging message')
+
+You can use 'LOG' in much the same way as you would use print
+statements to log debugging information while Zope is running.  You
+should remember that Zope can be configured to ignore log messages
+below certain levels of severity.  If you are not seeing your logging
+messages, make sure that Zope is configured to write them to the
+application log.
+
+In general the debugger is a much more powerful way to locate
+problems than using the logger.  However, for simple debugging tasks
+and for issuing warnings the logger works just fine.
+
+Other Testing and Debugging Facilities
+======================================
+
+There is a few other testing and debugging techniques and tools not
+commonly used to test Zope.  In this section we'll mention several of
+them.
+
+Debug Logging
+-------------
+
+Zope provides an analysis tool for debugging log output.  This output
+allows may give you hints as to where your application may be
+performing poorly, or not responding at all.  For example, since
+writing Zope products lets your write unrestricted Python code, it's
+very possibly to get yourself in a situation where you "hang" a Zope
+request, possibly by getting into a infinite loop.
+
+To try and detect at which point your application hangs, use the
+*requestprofiler.py* script in the *utilities* directory of your Zope
+installation.  To use this script, you must run Zope with the '-M'
+command line option.  This will turn on "detailed debug logging" that
+is necessary for the *requestprofiler.py* script to run.  The
+*requestprofiler.py* script has quite a few options which you can
+learn about with the '--help' switch.
+
+In general debug log analysis should be a last resort.  Use it when
+Zope is hanging and normal debugging and profiling is not helping you
+solve your problem.
+
+HTTP Benchmarking
+-----------------
+
+HTTP load testing is notoriously inaccurate.  However, it is useful
+to have a sense of how many requests your server can support.  Zope
+does not come with any HTTP load testing tools, but there are many
+available.  Apache's 'ab' program is a widely used free tool that can
+load your server with HTTP requests.
+
+Summary
+=======
+
+Zope provides a number of different debugging and testing facilities.
+The debugger allows you to interactively test your applications.
+Unit tests allow help you make sure that your application is develops
+correctly.  The logger allows you to do simple debugging and issue
+warnings.

Copied: zope2docs/branches/baijum-reorganize/zdgbook/ZODBPersistentComponents.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/ZODBPersistentComponents.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/ZODBPersistentComponents.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/ZODBPersistentComponents.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,596 @@
+##########################
+ZODB Persistent Components
+##########################
+
+Most Zope components live in the Zope Object DataBase (ZODB).
+Components that are stored in ZODB are said to be *persistent*.
+Creating persistent components is, for the most part, a trivial
+exercise, but ZODB does impose a few rules that persistent components
+must obey in order to work properly.  This chapter describes the
+persistence model and the interfaces that persistent objects can use
+to live inside the ZODB.
+
+Persistent Objects
+==================
+
+Persistent objects are Python objects that live for a long time. Most
+objects are created when a program is run and die when the program
+finishes. Persistent objects are not destroyed when the program ends,
+they are saved in a database.
+
+A great benefit of persistent objects is their transparency.  As a
+developer, you do not need to think about loading and unloading the
+state of the object from memory.  Zope's persistent machinery handles
+all of that for you.
+
+This is also a great benefit for application designers; you do not
+need to create your own kind of "data format" that gets saved to a
+file and reloaded again when your program stops and starts.  Zope's
+persistence machinery works with *any* kind of Python objects (within
+the bounds of a few simple rules) and as your types of objects grow,
+your database simply grows transparently with it.
+
+Persistence Example
+-------------------
+
+Here is a simple example of using ZODB outside of Zope.  If all you
+plan on doing is using persistent objects with Zope, you can skip
+this section if you wish.
+
+The first thing you need to do to start working with ZODB is to
+create a "root object".  This process involves first opening a
+"storage" , which is the actual backend storage location for your
+data.
+
+ZODB supports many pluggable storage back-ends, but for the purposes
+of this article we're going to show you how to use the 'FileStorage'
+back-end storage, which stores your object data in a file.  Other
+storages include storing objects in relational databases, Berkeley
+databases, and a client to server storage that stores objects on a
+remote storage server.
+
+
+To set up a ZODB, you must first install it.  ZODB comes with Zope,
+so the easiest way to install ZODB is to install Zope and use the
+ZODB that comes with your Zope installation.  For those of you who
+don't want all of Zope, but just ZODB, see the instructions for
+downloading ZODB from the `ZODB web page
+<http://wiki.zope.org/ZODB>`_.
+
+After installing ZODB, you can start to experiment with it right from
+the Python command line interpreter.  If you've installed Zope,
+before running this set of commands, shut down your Zope server, and
+"cd" to the "lib/python" directory of your Zope instance.  If you're
+using a "standalone" version of ZODB, you likely don't need to do
+this, and you'll be able to use ZODB by importing it from a standard
+Python package directory.  In either case, try the following set of
+commands::
+
+  chrism at saints:/opt/zope/lib/python$ python
+  Python 2.1.1 (#1, Aug  8 2001, 21:17:50) 
+  [GCC 2.95.2 20000220 (Debian GNU/Linux)] on linux2
+  Type "copyright", "credits" or "license" for more information. 
+  >>> from ZODB import FileStorage, DB
+  >>> storage = FileStorage.FileStorage('mydatabase.fs')
+  >>> db = DB( storage )
+  >>> connection = db.open()
+  >>> root = connection.root()
+
+Here, you create storage and use the 'mydatabse.fs' file to store the
+object information.  Then, you create a database that uses that
+storage.
+
+
+Next, the database needs to be "opened" by calling the 'open()'
+method.  This will return a connection object to the database.  The
+connection object then gives you access to the 'root' of the database
+with the 'root()' method.
+
+The 'root' object is the dictionary that holds all of your persistent
+objects.  For example, you can store a simple list of strings in the
+root object::
+
+      root['employees'] = ['Bob', 'Mary', 'Jo']
+
+Now, you have changed the persistent database by adding a new object,
+but this change is so far only temporary.  In order to make the
+change permanent, you must commit the current transaction::
+
+      get_transaction().commit()
+
+Transactions are ways to make a lot of changes in one atomic
+operation.  In a later article, we'll show you how this is a very
+powerful feature.  For now, you can think of committing transactions
+as "checkpoints" where you save the changes you've made to your
+objects so far.  Later on, we'll show you how to abort those changes,
+and how to undo them after they are committed.
+
+If you had used a relational database, you would have had to issue a
+SQL query to save even a simple python list like the above example.
+You would have also needed some code to convert a SQL query back into
+the list when you wanted to use it again.  You don't have to do any
+of this work when using ZODB.  Using ZODB is almost completely
+transparent, in fact, ZODB based programs often look suspiciously
+simple!
+
+Working with simple python types is useful, but the real power of
+ZODB comes out when you store your own kinds of objects in the
+database.  For example, consider a class that represents a employee::
+
+  from Persistence import Persistent
+
+  class Employee(Persistent):
+
+      def setName(self, name):
+          self.name = name
+
+
+Calling 'setName' will set a name for the employee.  Now, you can put
+Employee objects in your database::
+
+  for name in ['Bob', 'Mary', 'Joe']:
+      employee = Employee()
+      employee.setName(name)
+      root['employees'].append(employee)
+
+  get_transaction().commit()
+
+Don't forget to call 'commit()', so that the changes you have made so
+far are committed to the database, and a new transaction is begun.
+
+Persistent Rules
+================
+
+There are a few rules that must be followed when your objects are
+persistent.
+
+- Your objects, and their attributes, must be "pickleable".
+
+- Your object cannot have any attributes that begin with '_p_'.
+
+- Attributes of your object that begin with '_v_' are "volatile" and
+  are not saved to the database (see next section).
+
+- You must explicitly signal any changes made to mutable attributes
+  (such as instances, lists, and dictionaries) or use persistent
+  versions of mutable objects, like 'ZODB.PersistentMapping' (see
+  below for more information on 'PersistentMapping'.)
+
+In this section, we'll look at each of these special rules one by
+one.
+
+The first rules says that your objects must be pickleable.  This
+means that they can be serialized into a data format with the
+"pickle" module.  Most python data types (numbers, lists,
+dictionaries) can be pickled.  Code objects (method, functions,
+classes) and file objects (files, sockets) *cannot* be pickled.
+Instances can be persistent objects if:
+
+- They subclass 'Persistence.Persistent'
+
+- All of their attributes are pickleable
+
+The second rule is that none of your objects attributes can begin
+with '_p_'.  For example, '_p_b_and_j' would be an illegal object
+attribute.  This is because the persistence machinery reserves all of
+these names for its own purposes.
+
+The third rule is that all object attributes that begin with '_v_'
+are "volatile" and are not saved to the database.  This means that as
+long as the persistent object is in Zope memory cache, volatile
+attributes can be used.  When the object is deactivated (removed from
+memory) volatile attributes are thrown away.
+
+Volatile attributes are useful for data that is good to cache for a
+while but can often be thrown away and easily recreated.  File
+connections, cached calculations, rendered templates, all of these
+kinds of things are useful applications of volatile attributes. You
+must exercise care when using volatile attributes.  Since you have
+little control over when your objects are moved in and out of memory,
+you never know when your volatile attributes may disappear.
+
+The fourth rule is that you must signal changes to mutable types.
+This is because persistent objects can't detect when mutable types
+change, and therefore, doesn't know whether or not to save the
+persistent object or not.
+
+For example, say you had a list of names as an attribute of your
+object called 'departments' that you changed in a method called
+'addDepartment'::
+
+  class DepartmentManager(Persistent):
+
+      def __init__(self):
+          self.departments = []
+
+      def addDepartment(self, department):
+          self.departments.append(department)
+
+When you call the 'addDepartment' method you change a mutable type,
+'departments' but your persistent object will not save that change.
+
+There are two solutions to this problem.  First, you can assign a
+special flag, '_p_changed'::
+
+  def addDepartment(self, department):
+      self.department.append(department)
+      self._p_changed = 1
+
+Remember, '_p_' attributes do something special to the persistence
+machinery and are reserved names. Assigning 1 to '_p_changed' tells
+the persistence machinery that you changed the object, and that it
+should be saved.
+
+Another technique is to use the mutable attribute as though it were
+immutable. In other words, after you make changes to a mutable
+object, reassign it::
+
+  def addDepartment(self, department):
+      departments = self.departments
+      departments.append(department)
+      self.department = departments
+
+Here, the 'self.departments' attribute was re-assigned at the end of
+the function to the "working copy" object 'departments'.  This
+technique is cleaner because it doesn't have any explicit
+'_p_changed' settings in it, but this implicit triggering of the
+persistence machinery should always be understood, otherwise use the
+explicit syntax.
+
+A final option is to use persistence-aware mutable attributes such as
+'PersistentMapping', and 'IOBTree'. 'PersistentMapping' is a mapping
+class that notifies ZODB when you change the mapping. You can use
+instances of 'PersistentMapping' in place of standard Python
+dictionaries and not worry about signaling change by reassigning the
+attribute or using '_p_changed'. Zope's Btree classes are also
+persistent-aware mutable containers. This solution can be cleaner
+than using mutable objects immutably, or signaling change manually
+assuming that there is a persistence-aware class available that meets
+your needs.
+
+Transactions and Persistent Objects
+===================================
+
+When changes are saved to ZODB, they are saved in a *transaction*.
+This means that either all changes are saved, or none are saved.  The
+reason for this is data consistency.  Imagine the following scenario:
+
+1. A user makes a credit card purchase at the sandwich.com website.
+
+2. The bank debits their account.
+
+3. An electronic payment is made to sandwich.com.
+
+Now imagine that an error happens during the last step of this
+process, sending the payment to sandwich.com.  Without transactions,
+this means that the account was debited, but the payment never went
+to sandwich.com!  Obviously this is a bad situation.  A better
+solution is to make all changes in a transaction:
+
+1. A user makes a credit card purchase at the sandwich.com website.
+
+2. The transaction begins
+
+3. The bank debits their account.
+
+4. An electronic payment is made to sandwich.com.
+
+5. The transaction commits
+
+Now, if an error is raised anywhere between steps 2 and 5, *all*
+changes made are thrown away, so if the payment fails to go to
+sandwich.com, the account won't be debited, and if debiting the
+account raises an error, the payment won't be made to sandwich.com,
+so your data is always consistent.
+
+When using your persistent objects with Zope, Zope will automatically
+*begin* a transaction when a web request is made, and *commit* the
+transaction when the request is finished.  If an error occurs at any
+time during that request, then the transaction is *aborted*, meaning
+all the changes made are thrown away.
+
+If you want to *intentionally* abort a transaction in the middle of a
+request, then just raise an error at any time.  For example, this
+snippet of Python will raise an error and cause the transaction to
+abort::
+
+  raise SandwichError('Not enough peanut butter.')
+
+A more likely scenario is that your code will raise an exception when
+a problem arises. The great thing about transactions is that you
+don't have to include cleanup code to catch exceptions and undo
+everything you've done up to that point. Since the transaction is
+aborted the changes made in the transaction will not be saved.
+
+Because Zope does transaction management for you, most of the time
+you do not need to explicitly begin, commit or abort your own
+transactions.  For more information on doing transaction management
+manually, see the links at the end of this chapter that lead to more
+detailed tutorials of doing your own ZODB programming.
+
+
+Subtransactions
+---------------
+
+Zope waits until the transaction is committed to save all the changes
+to your objects.  This means that the changes are saved in memory.
+If you try to change more objects than you have memory in your
+computer, your computer will begin to swap and thrash, and maybe even
+run you out of memory completely.  This is bad. The easiest solution
+to this problem is to not change huge quantities of data in one
+transaction.
+
+If you need to spread a transaction out of lots of data, however, you
+can use subtransactions.  Subtransactions allow you to manage Zope's
+memory usage yourself, so as to avoid swapping during large
+transactions.
+
+Subtransactions allow you to make huge transactions. Rather than
+being limited by available memory, you are limited by available disk
+space.  Each subtransaction commit writes the current changes out to
+disk and frees memory to make room for more changes.
+
+To commit a subtransaction, you first need to get a hold of a
+transaction object.  Zope adds a function to get the transaction
+objects in your global namespace, 'get_transaction', and then call
+'commit(1)' on the transaction::
+
+  get_transaction().commit(1)
+
+You must balance speed, memory, and temporary storage concerns when
+deciding how frequently to commit subtransactions. The more
+subtransactions, the less memory used, the slower the operation, and
+the more temporary space used. Here's and example of how you might
+use subtransactions in your Zope code::
+
+  tasks_per_subtransaction = 10
+  i = 0
+  for task in tasks:
+      process(task)
+      i = i + 1
+      if i % tasks_per_subtransaction == 0:
+          get_transaction().commit(1)
+
+This example shows how to commit a subtransaction at regular
+intervals while processing a number of tasks.
+
+Threads and Conflict Errors
+---------------------------
+
+Zope is a multi-threaded server.  This means that many different
+clients may be executing your Python code in different threads.  For
+most cases, this is not an issue and you don't need to worry about
+it, but there are a few cases you should look out for.
+
+The first case involves threads making lots of changes to objects and
+writing to the database.  The way ZODB and threading works is that
+each thread that uses the database gets its own *connection* to the
+database.  Each connection gets its own *copy* of your object.  All
+of the threads can read and change any of the objects.  ZODB keeps
+all of these objects synchronized between the threads. The upshot is
+that you don't have to do any locking or thread synchronization
+yourself. Your code can act as though it is single threaded.
+
+However, synchronization problems can occur when objects are changed
+by two different threads at the same time.
+
+Imagine that thread 1 gets its own copy of object A, as does thread
+2.  If thread 1 changes its copy of A, then thread 2 will not see
+those changes until thread 1 commits them.  In cases where lots of
+objects are changing, this can cause thread 1 and 2 to try and commit
+changes to object 1 at the same time.
+
+When this happens, ZODB lets one transaction do the commit (it
+"wins") and raises a 'ConflictError' in the other thread (which
+"looses"). The looser can elect to try again, but this may raise yet
+another 'ConflictError' if many threads are trying to change object
+A. Zope does all of its own transaction management and will retry a
+losing transaction three times before giving up and raising the
+'ConflictError' all the way up to the user.
+
+
+Resolving Conflicts
+-------------------
+
+If a conflict happens, you have two choices. The first choice is that
+you live with the error and you try again. Statistically, conflicts
+are going to happen, but only in situations where objects are
+"hot-spots".  Most problems like this can be "designed away"; if you
+can redesign your application so that the changes get spread around
+to many different objects then you can usually get rid of the hot
+spot.
+
+
+Your second choice is to try and *resolve* the conflict. In many
+situations, this can be done. For example, consider the following
+persistent object::
+
+  class Counter(Persistent):
+
+      self.count = 0
+
+      def hit(self):
+          self.count = self.count + 1
+
+This is a simple counter.  If you hit this counter with a lot of
+requests though, it will cause conflict errors as different threads
+try to change the count attribute simultaneously.
+
+But resolving the conflict between conflicting threads in this case
+is easy.  Both threads want to increment the self.count attribute by
+a value, so the resolution is to increment the attribute by the sum
+of the two values and make both commits happy; no 'ConflictError' is
+raised.
+
+
+To resolve a conflict, a class should define an '_p_resolveConflict'
+method. This method takes three arguments.
+
+'oldState' -- The state of the object that the changes made by the
+current transaction were based on. The method is permitted to modify
+this value.
+
+'savedState' -- The state of the object that is currently stored in
+the database. This state was written after 'oldState' and reflects
+changes made by a transaction that committed before the current
+transaction. The method is permitted to modify this value.
+
+'newState' -- The state after changes made by the current
+transaction.  The method is *not* permitted to modify this
+value. This method should compute a new state by merging changes
+reflected in 'savedState' and 'newState', relative to 'oldState'.
+
+The method should return the state of the object after resolving the
+differences.
+
+Here is an example of a '_p_resolveConflict' in the 'Counter' class::
+
+  class Counter(Persistent):
+
+      self.count = 0
+
+      def hit(self):
+          self.count = self.count + 1
+
+      def _p_resolveConflict(self, oldState, savedState, newState):
+
+          # Figure out how each state is different:
+          savedDiff= savedState['count'] - oldState['count']
+          newDiff= newState['count']- oldState['count']
+
+          # Apply both sets of changes to old state:
+          oldState['count'] = oldState['count'] + savedDiff + newDiff
+
+          return oldState
+
+In the above example, '_p_resolveConflict' resolves the difference
+between the two conflicting transactions.
+
+Threadsafety of Non-Persistent Objects
+======================================
+
+ZODB takes care of threadsafety for persistent objects. However, you
+must handle threadsafey yourself for non-persistent objects which are
+shared between threads.
+
+Mutable Default Arguments
+-------------------------
+
+One tricky type of non-persistent, shared objects are mutable default
+arguments to functions, and methods.  Default arguments are useful
+because they are cached for speed, and do not need to be recreated
+every time the method is called.  But if these cached default
+arguments are mutable, one thread may change (mutate) the object when
+another thread is using it, and that can be bad.  So, code like::
+
+        def foo(bar=[]):
+            bar.append('something')
+
+
+Could get in trouble if two threads execute this code because lists
+are mutable.  There are two solutions to this problem:
+
+- Don't use mutable default arguments. (Good)
+
+- If you use them, you cannot change them.  If you want to change
+  them, you will need to implement your own locking. (Bad)
+
+We recommend the first solution because mutable default arguments are
+confusing, generally a bad idea in the first place.
+
+Shared Module Data
+------------------
+
+Objects stored in modules but not in the ZODB are not persistent and
+not-thread safe. In general it's not a good idea to store data (as
+opposed to functions, and class definitions) in modules when using
+ZODB.
+
+
+If you decide to use module data which can change you'll need to
+protect it with a lock to ensure that only one thread at a time can
+make changes.
+
+
+For example::
+
+  from threading import Lock
+  queue=[]
+  l=Lock()
+
+  def put(obj):
+      l.acquire()
+      try:
+          queue.append(obj)
+      finally:
+          l.release()
+
+  def get():
+      l.acquire()
+      try:
+          return queue.pop()
+      finally:
+          l.release()
+
+Note, in most cases where you are tempted to use shared module data,
+you can likely achieve the same result with a single persistent
+object. For example, the above queue could be replaced with a single
+instance of this class::
+
+  class Queue(Persistent):
+
+      def __init__(self):
+          self.list=[]
+
+      def put(self, obj):
+          self.list=self.list + [obj]
+
+      def get(self):
+          obj=self.list[-1]
+          self.list=self.list[0:-1]
+          return obj
+
+Notice how this class uses the mutable object 'self.list'
+immutably. If this class used 'self.list.pop' and 'self.list.append',
+then the persistence machinary would not notice that 'self.list' had
+changed.
+
+Shared External Resources
+=========================
+
+A final category of data for which you'll need to handle
+thread-safety is external resources such as files in the filesystem,
+and other processes. In practice, these concerns rarely come up.
+
+Other ZODB Resources
+====================
+
+This chapter has only covered the most important features of ZODB
+from a Zope developer's perspective. Check out some of these sources
+for more in depth information:
+
+- Andrew Kuchling's `ZODB pages <http://www.kuchling.com/zodb/>`_
+  include lots of information included a programmer's guide and links
+  to ZODB mailing lists.
+
+- `ZODB Wiki <http://wiki.zope.org/ZODB>`_ has information about
+  current ZODB projects.
+
+- `ZODB UML
+  Model <http://www.zope.org/Documentation/Developer/Models/ZODB>`_ has
+  the nitty gritty details on ZODB.
+
+- Paper `Introduction to the Zope Object Database
+  <http://www.python.org/workshops/2000-01/proceedings/papers/fulton/zodb3.html>`_
+  by Jim Fulton, presented at the 8th Python Conference.
+
+Summary
+=======
+
+The ZODB is a complex and powerful system. However using persistent
+objects is almost completely painless. Seldom do you need to concern
+yourself with thread safety, transactions, conflicts, memory
+management, and database replication. ZODB takes care of these things
+for you. By following a few simple rules you can create persistent
+objects that just work.
+

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/bootstrap.py
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/bootstrap.py	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/bootstrap.py	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,77 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Bootstrap a buildout-based project
-
-Simply run this script in a directory containing a buildout.cfg.
-The script accepts buildout command-line options, so you can
-use the -c option to specify an alternate configuration file.
-
-$Id: bootstrap.py 90478 2008-08-27 22:44:46Z georgyberdyshev $
-"""
-
-import os, shutil, sys, tempfile, urllib2
-
-tmpeggs = tempfile.mkdtemp()
-
-is_jython = sys.platform.startswith('java')
-
-try:
-    import pkg_resources
-except ImportError:
-    ez = {}
-    exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
-                         ).read() in ez
-    ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
-
-    import pkg_resources
-
-if sys.platform == 'win32':
-    def quote(c):
-        if ' ' in c:
-            return '"%s"' % c # work around spawn lamosity on windows
-        else:
-            return c
-else:
-    def quote (c):
-        return c
-
-cmd = 'from setuptools.command.easy_install import main; main()'
-ws  = pkg_resources.working_set
-
-if is_jython:
-    import subprocess
-    
-    assert subprocess.Popen([sys.executable] + ['-c', quote(cmd), '-mqNxd', 
-           quote(tmpeggs), 'zc.buildout'], 
-           env=dict(os.environ,
-               PYTHONPATH=
-               ws.find(pkg_resources.Requirement.parse('setuptools')).location
-               ),
-           ).wait() == 0
-
-else:
-    assert os.spawnle(
-        os.P_WAIT, sys.executable, quote (sys.executable),
-        '-c', quote (cmd), '-mqNxd', quote (tmpeggs), 'zc.buildout',
-        dict(os.environ,
-            PYTHONPATH=
-            ws.find(pkg_resources.Requirement.parse('setuptools')).location
-            ),
-        ) == 0
-
-ws.add_entry(tmpeggs)
-ws.require('zc.buildout')
-import zc.buildout.buildout
-zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
-shutil.rmtree(tmpeggs)

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/buildout.cfg
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/buildout.cfg	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/buildout.cfg	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,22 +0,0 @@
-[buildout]
-develop =
-parts =
-    stxpy
-
-eggs-directory = ${buildout:directory}/eggs
-versions = versions
-unzip = true
-eggs =
-
-[versions]
-zc.buildout =
-zc.recipe.egg =
-
-[stxpy]
-recipe = zc.recipe.egg
-eggs =
-    Sphinx
-interpreter = stxpy
-scripts =
-    sphinx-build
-    sphinx-quickstart

Copied: zope2docs/branches/baijum-reorganize/zdgbook/index.rst (from rev 104983, zope2docs/branches/baijum-reorganize/zdgbook/source/index.rst)
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/index.rst	                        (rev 0)
+++ zope2docs/branches/baijum-reorganize/zdgbook/index.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -0,0 +1,17 @@
+Zope Developer's Guide
+======================
+
+.. toctree::
+   :numbered:
+   :maxdepth: 2
+
+   Introduction.rst
+   GettingStarted.rst
+   ComponentsAndInterfaces.rst
+   ObjectPublishing.rst
+   Products.rst
+   ZODBPersistentComponents.rst
+   Acquisition.rst
+   Security.rst
+   TestingAndDebugging.rst
+   AppendixA.rst

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/Acquisition.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/Acquisition.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/Acquisition.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,457 +0,0 @@
-###########
-Acquisition
-###########
-
-Acquisition is a mechanism that allows objects to obtain attributes
-from their environment.  It is similar to inheritance, except that,
-rather than searching an inheritance hierarchy to obtain attributes,
-a containment hierarchy is traversed.
-
-
-Introductory Example
-====================
-
-Zope implements acquisition with "Extension Class" mix-in classes. To
-use acquisition your classes must inherit from an acquisition base
-class. For example::
-
-  import ExtensionClass, Acquisition
-
-  class C(ExtensionClass.Base):
-    color = 'red'
-
-  class A(Acquisition.Implicit):
-
-    def report(self):
-      print self.color
-
-  a = A()
-  c = C()
-  c.a = A()
-
-  c.a.report() # prints 'red'
-
-  d = C()
-  d.color = 'green'
-  d.a = a
-
-  d.a.report() # prints 'green'
-
-  a.report() # raises an attribute error
-
-The class 'A' inherits acquisition behavior from
-'Acquisition.Implicit'.  The object, 'a', "has" the color of objects
-'c' and 'd' when it is accessed through them, but it has no color by
-itself.  The object 'a' obtains attributes from its environment,
-where its environment is defined by the access path used to reach
-'a'.
-
-Acquisition Wrappers
-====================
-
-When an object that supports acquisition is accessed through an
-extension class instance, a special object, called an acquisition
-wrapper, is returned.  In the example above, the expression 'c.a'
-returns an acquisition wrapper that contains references to both 'c'
-and 'a'.  It is this wrapper that performs attribute lookup in 'c'
-when an attribute cannot be found in 'a'.
-
-Acquisition wrappers provide access to the wrapped objects through
-the attributes 'aq_parent', 'aq_self', 'aq_base'.  In the example
-above, the expressions::
-
-  'c.a.aq_parent is c'
-
-and::
-
-  'c.a.aq_self is a'
-
-
-both evaluate to true, but the expression::
-
-  'c.a is a'
-
-evaluates to false, because the expression 'c.a' evaluates to an
-acquisition wrapper around 'c' and 'a', not 'a' itself.
-
-The attribute 'aq_base' is similar to 'aq_self'.  Wrappers may be
-nested and 'aq_self' may be a wrapped object.  The 'aq_base'
-attribute is the underlying object with all wrappers removed.
-
-You can manually wrap an instance of an object that inherits from an
-acquisition base class by using its '__of__' method. For example::
-
-  class A(Acquisition.Implicit):
-      pass
-
-  a = A()
-  a.color = 'red'
-  b = A()
-  a.b = b
-
-  print b.__of__(a).color # prints red
-
-
-The expression 'b.__of__(a)' wraps 'b' in an acquisition wrapper
-explicitly, and returns the acquisition wrapper.  The 'color'
-attrribute of 'a' is found via acquisition when this expression is
-executed.
-
-
-Explicit and Implicit Acquisition
-=================================
-
-Two styles of acquisition are supported: implicit and explicit
-acquisition.
-
-Implicit acquisition
---------------------
-
-Implicit acquisition is so named because it searches for
-attributes from the environment automatically whenever an
-attribute cannot be obtained directly from an object or through
-inheritance.
-
-An attribute can be implicitly acquired if its name does not
-begin with an underscore.
-
-To support implicit acquisition, your class should inherit from
-the mix-in class 'Acquisition.Implicit'.
-
-Explicit Acquisition
---------------------
-
-When explicit acquisition is used, attributes are not automatically
-obtained from the environment.  Instead, the method 'aq_acquire' must
-be used. For example::
-
-  print c.a.aq_acquire('color')
-
-To support explicit acquisition, your class should inherit from the
-mix-in class 'Acquisition.Explicit'.
-
-Controlling Acquisition
-=======================
-
-A class (or instance) can provide attribute by attribute control over
-acquisition.  Your should subclass from 'Acquisition.Explicit', and
-set all attributes that should be acquired to the special value
-'Acquisition.Acquired'.  Setting an attribute to this value also
-allows inherited attributes to be overridden with acquired ones.  For
-example::
-
-  class C(Acquisition.Explicit):
-     id=1
-     secret=2
-     color=Acquisition.Acquired
-     __roles__=Acquisition.Acquired
-
-The *only* attributes that are automatically acquired from containing
-objects are 'color', and '__roles__'.  Note that the '__roles__'
-attribute is acquired even though its name begins with an underscore.
-In fact, the special 'Acquisition.Acquired' value can be used in
-'Acquisition.Implicit' objects to implicitly acquire selected objects
-that smell like private objects.
-
-Sometimes, you want to dynamically make an implicitly acquiring
-object acquire explicitly. You can do this by getting the object's
-'aq_explicit' attribute. This attribute provides the object with an
-explicit wrapper that places the original implicit wrapper.
-
-Filtered Acquisition
-====================
-
-The acquisition method, 'aq_acquire', accepts two optional
-arguments. The first of the additional arguments is a "filtering"
-function that is used when considering whether to acquire an object.
-The second of the additional arguments is an object that is passed as
-extra data when calling the filtering function and which defaults to
-'None'.  The filter function is called with five arguments:
-
-- The object that the 'aq_acquire' method was called on,
-
-- The object where an object was found,
-
-- The name of the object, as passed to 'aq_acquire',
-
-- The object found, and
-
-- The extra data passed to 'aq_acquire'.
-
-If the filter returns a true object that the object found is
-returned, otherwise, the acquisition search continues.
-
-For example, in::
-
-  from Acquisition import Explicit
-
-  class HandyForTesting:
-      def __init__(self, name):
-          self.name = name
-      def __str__(self):
-          return "%s(%s)" % (self.name, self.__class__.__name__)
-      __repr__ = __str__
-
-  class E(Explicit, HandyForTesting): pass
-
-  class Nice(HandyForTesting):
-      isNice = 1
-      def __str__(self):
-          return HandyForTesting.__str__(self) + ' and I am nice!'
-      __repr__ = __str__
-
-  a = E('a')
-  a.b = E('b')
-  a.b.c = E('c')
-  a.p = Nice('spam')
-  a.b.p = E('p')
-
-  def find_nice(self, ancestor, name, object, extra):
-      return hasattr(object,'isNice') and object.isNice
-
-  print a.b.c.aq_acquire('p', find_nice)
-
-The filtered acquisition in the last line skips over the first
-attribute it finds with the name 'p', because the attribute doesn't
-satisfy the condition given in the filter. The output of the last
-line is::
-
-  spam(Nice) and I am nice!
-
-Filtered acquisition is rarely used in Zope.
-
-Acquiring from Context
-======================
-
-Normally acquisition allows objects to acquire data from their
-containers. However an object can acquire from objects that aren't
-its containers.
-
-Most of the example's we've seen so far show establishing of an
-acquisition *context* using 'getattr' symanitics. For example, 'a.b'
-is a reference to 'b' in the context of 'a'.
-
-
-You can also manuallyset acquisition context using the '__of__'
-method.  For example::
-
-  from Acquisition import Implicit
-  class C(Implicit): pass
-  a = C()
-  b = C()
-  a.color = "red"
-  print b.__of__(a).color # prints red
-
-In this case, 'a' does not contain 'b', but it is put in 'b''s
-context using the '__of__' method.
-
-Here's another subtler example that shows how you can construct an
-acquisition context that includes non-container objects::
-
-  from Acquisition import Implicit
-
-  class C(Implicit):
-      def __init__(self, name):
-          self.name = name
-
-  a = C("a")
-  a.b = C("b")
-  a.b.color = "red"
-  a.x = C("x")
-
-  print a.b.x.color # prints red
-
-Even though 'b' does not contain 'x', 'x' can acquire the 'color'
-attribute from 'b'. This works because in this case, 'x' is accessed
-in the context of 'b' even though it is not contained by 'b'.
-
-Here acquisition context is defined by the objects used to access
-another object.
-
-Containment Before Context
-==========================
-
-If in the example above suppose both 'a' and 'b' have an 'color'
-attribute::
-
-  a = C("a")
-  a.color = "green"
-  a.b = C("b")
-  a.b.color = "red"
-  a.x = C("x")
-
-  print a.b.x.color # prints green
-
-
-Why does 'a.b.x.color' acquire 'color' from 'a' and not from 'b'?
-The answer is that an object acquires from its containers before
-non-containers in its context.
-
-To see why consider this example in terms of expressions using the
-'__of__' method::
-
-   a.x -> x.__of__(a)
-
-   a.b -> b.__of__(a)
-
-   a.b.x -> x.__of__(a).__of__(b.__of__(a))
-
-Keep in mind that attribute lookup in a wrapper is done by trying to
-look up the attribute in the wrapped object first and then in the
-parent object.  So in the expressions above proceeds from left to
-right.
-
-
-The upshot of these rules is that attributes are looked up by
-containment before context.
-
-This rule holds true also for more complex examples. For example,
-'a.b.c.d.e.f.g.attribute' would search for 'attribute' in 'g' and all
-its containers first. (Containers are searched in order from the
-innermost parent to the outermost container.) If the attribute is not
-found in g or any of its containers, then the search moves to 'f' and
-all its containers, and so on.
-
-Additional Attributes and Methods
-=================================
-
-You can use the special method 'aq_inner' to access an object wrapped
-only by containment. So in the example above::
-
-  a.b.x.aq_inner
-
-is equivalent to::
-
-  a.x
-
-You can find out the acquisition context of an object using the
-'aq_chain' method like so::
-
-  a.b.x.aq_chain # returns [x, b, a]
-
-You can find out if an object is in the acquisition context of
-another object using the 'aq_inContextOf' method. For example::
-
-  a.b.x.aq_inContextOf(a.b) # returns 1
-
-
-You can also pass an additional argument to 'aq_inContextOf' to
-indicate whether to only check containment rather than the full
-acquisition context. For example::
-
-  a.b.x.aq_inContextOf(a.b, 1) # returns 0
-
-Note: as of this writing the 'aq_inContextOf' examples don't
-work. According to Jim, this is because 'aq_inContextOf' works by
-comparing object pointer addresses, which (because they are actually
-different wrapper objects) doesn't give you the expected results. He
-acknowledges that this behavior is controversial, and says that there
-is a collector entry to change it so that you would get the answer
-you expect in the above. (We just need to get to it).
-
-
-Acquisition Module Functions
-----------------------------
-
-In addition to using acquisition attributes and methods directly on
-objects you can use similar functions defined in the 'Acquisition'
-module. These functions have the advantage that you don't need to
-check to make sure that the object has the method or attribute before
-calling it.
-
-'aq_acquire(object, name [, filter, extra, explicit, default, containment])' -- Acquires an object with the given name.
-
-This function can be used to explictly acquire when using explicit
-acquisition and to acquire names that wouldn't normally be acquired.
-
-The function accepts a number of optional arguments:
-
-- 'filter' -- A callable filter object that is used to decide if an
-  object should be acquired.
-
-  The filter is called with five arguments:
-
-  - The object that the aq_acquire method was called on,
-
-  - The object where an object was found,
-
-  - The name of the object, as passed to aq_acquire,
-
-  - The object found, and
-
-  - The extra argument passed to aq_acquire.
-
-  If the filter returns a true object that the object found is
-  returned, otherwise, the acquisition search continues.
-
-- 'extra' -- extra data to be passed as the last argument to the
-  filter.
-
-- 'explicit' -- A flag (boolean value) indicating whether explicit
-  acquisition should be used. The default value is true.  If the flag
-  is true, then acquisition will proceed regardless of whether
-  wrappers encountered in the search of the acquisition hierarchy are
-  explicit or implicit wrappers. If the flag is false, then parents
-  of explicit wrappers are not searched.
-
-  This argument is useful if you want to apply a filter without
-  overriding explicit wrappers.
-
-- 'default' -- A default value to return if no value can be acquired.
-
-- 'containment' -- A flag indicating whether the search should be
-  limited to the containment hierarchy.
-
-In addition, arguments can be provided as keywords.
-
-- 'aq_base(object)' -- Return the object with all wrapping removed.
-
-- 'aq_chain(object [, containment])' -- Return a list containing the
-  object and it's acquisition parents. The optional argument,
-  'containment', controls whether the containment or access hierarchy
-  is used.
-
-- 'aq_get(object, name [, default, containment])' -- Acquire an
-  attribute, name. A default value can be provided, as can a flag
-  that limits search to the containment hierarchy.
-
-- 'aq_inner(object)' -- Return the object with all but the innermost
-  layer of wrapping removed.
-
-- 'aq_parent(object)' -- Return the acquisition parent of the object
-  or 'None' if the object is unwrapped.
-
-- 'aq_self(object)' -- Return the object with one layer of wrapping
-  removed, unless the object is unwrapped, in which case the object
-  is returned.
-
-In most cases it is more convenient to use these module functions
-instead of the acquisition attributes and methods directly.
-
-Acquisition and Methods
-=======================
-
-Python methods of objects that support acquisition can use acquired
-attributes.  When a Python method is called on an object that is
-wrapped by an acquisition wrapper, the wrapper is passed to the
-method as the first argument.  This rule also applies to user-defined
-method types and to C methods defined in pure mix-in classes.
-
-Unfortunately, C methods defined in extension base classes that
-define their own data structures, cannot use aquired attributes at
-this time.  This is because wrapper objects do not conform to the
-data structures expected by these methods. In practice, you will
-seldom find this a problem.
-
-Conclusion
-==========
-
-Acquisition provides a powerful way to dynamically share information
-between objects. Zope using acquisition for a number of its key
-features including security, object publishing, and DTML variable
-lookup. Acquisition also provides an elegant solution to the problem
-of circular references for many classes of problems. While
-acquisition is powerful, you should take care when using acquisition
-in your applications. The details can get complex, especially with
-the differences between acquiring from context and acquiring from
-containment.

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/AppendixA.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/AppendixA.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/AppendixA.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,123 +0,0 @@
-#################################
-Appendix A: Zope Core Permissions
-#################################
-
-This is a list of standard permissions included with Zope.  It is a
-good idea to use these permissions when applicable with your Zope
-products, rather than creating new ones.  A list of built-in Zope
-permissions are available in Zope source code:
-``src/AccessControl/Permissions.py``.
-
-Core Permissions
-================
-
-- Access contents information -- get "directory listing" info
-
-- Add Accelerated HTTP Cache Managers -- add HTTP Cache Manager objects
-
-- Add Database Methods -- add ZSQL Method objects
-
-- Add Documents, Images, and Files -- add DTML Method/Document objects,
-  Image objects, and File objects
-
-- Add External Methods  -- add External Method objects
-
-- Add Folders -- add Folder objects
-
-- Add MailHost objects  -- add MailHost objects
-
-- Add Python Scripts  -- Add Python Script objects
-
-- Add RAM Cache Managers  -- Add RAM Cache manager objects
-
-- Add Site Roots -- add Site Root objects
-
-- Add User Folders  -- add User Folder objects
-
-- Add Versions  -- add Version objects
-
-- Add Virtual Host Monsters  -- add Virtual Host Monster objects
-
-- Add Vocabularies  -- add Vocabulary objects (ZCatalog-related)
-
-- Add ZCatalogs  -- add ZCatalog objects
-
-- Add Zope Tutorials  -- add Zope Tutorial objects
-
-- Change DTML Documents -- modify DTML Documents
-
-- Change DTML Methods  -- modify DTML Methods
-
-- Change Database Connections  -- change database connection objects
-
-- Change Database Methods  -- change ZSQL method objects
-
-- Change External Methods -- change External Method objects
-
-- Change Images and Files  -- change Image and File objects
-
-- Change Python Scripts  -- change Python Script objects
-
-- Change Versions  -- change Version objects
-
-- Change bindings  -- change bindings (for Python Scripts)
-
-- Change cache managers  -- change cache manager objects
-
-- Change cache settings  -- change cache settings (cache mgr parameters)
-
-- Change configuration  -- generic
-
-- Change permissions  -- change permissions
-
-- Change proxy roles  -- change proxy roles
-
-- Create class instances  -- used for ZClass permission mappings
-
-- Delete objects  -- delete objects
-
-- Edit Factories  -- edit Factory objects (ZClass)
-
-- FTP access  -- allow FTP access to this object
-
-- Import/Export objects  -- export and import objects
-
-- Join/leave Versions  -- join and leave Zope versions
-
-- Manage Access Rules -- manage access rule objects
-
-- Manage Vocabulary  -- manage Vocabulary objects
-
-- Manage Z Classes  -- Manage ZClass objects (in the control panel)
-
-- Manage ZCatalog Entries  -- catalog and uncatalog objects
-
-- Manage properties -- manage properties of an object
-
-- Manage users  -- manage Zope users
-
-- Open/Close Database Connections  -- open and close database connections    
-
-- Query Vocabulary -- query Vocabulary objects (ZCatalog-related)
-
-- Save/discard Version changes -- save or discard Zope version changes
-
-- Search ZCatalog -- search a ZCatalog instance
-
-- Take ownership  -- take ownership of an object
-
-- Test Database Connections  -- test database connection objects
-
-- Undo changes  -- undo changes to the ZODB (e.g. use the Undo tab)
-
-- Use Database Methods  -- use ZSQL methods
-
-- Use Factories  -- use Factory objects (ZClass-related)
-
-- Use mailhost services -- use MailHost object services
-
-- View -- view or execute an object
-
-- View History -- view ZODB history of an object
-
-- View management screens -- view management screens related to an object

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/ComponentsAndInterfaces.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/ComponentsAndInterfaces.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/ComponentsAndInterfaces.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,333 +0,0 @@
-#########################
-Components and Interfaces
-#########################
-
-Zope uses a component architecture internally in many places.  Zope
-components is nothing but Python objects with interfaces that
-describe them.  As a Zope developer you can use interfaces right now
-to build your Zope components.
-
-Zope Components
-===============
-
-Components are objects that are associated with interfaces.  An
-interface is a Python object that describes how you work with other
-Python objects.  In this chapter, you'll see some simple examples of
-creating components, and a description of interfaces and how they
-work.
-
-Here is a very simple component that says hello.  Like all
-components, this one generally consists of two pieces, an interface,
-and an implementation::
-
-  from zope.interface import Interface
-  from zope.interface import implements
-
-  class IHello(Interface):
-      """The Hello interface provides greetings."""
-
-      def hello(name):
-          """Say hello to the name"""
-
-  class HelloComponent(object):
-
-      implements(IHello)
-
-      def hello(self, name):
-          return "hello %s!" % name
-
-Let's take a look at this step by step.  Here, you see two Python
-class statements.  The first class statement creates the *interface*,
-and the second class statement creates the *implementation*.
-
-The first class statement creates the ``IHello`` interface.  This
-interface describes one method, called ``hello``.  Notice that there
-is no implementation for this method, interfaces do not define
-behavior, they just describe a specification.
-
-The second ``class`` statement creates the ``HelloComponent`` class.
-This class is the actual component that *does* what ``IHello``
-*describes*.  This is usually referred to as the *implementation* of
-``IHello``.  In order for you to know what interfaces
-``HelloComponent`` implements, it must somehow associate itself with
-an interface.  The ``implements`` function call inside the class does
-just that.  It says, "I implement these interfaces".  In this case,
-``HelloComponent`` asserts that it implements one interface,
-``IHello``.
-
-The interface describes how you would work with the object, but it
-doesn't dictate how that description is implemented.  For example,
-here's a more complex implementation of the ``Hello`` interface::
-
-  import xmlrpclib
-  class XMLRPCHello:
-
-      implementats(IHello)
-
-      def hello(self, name):
-          """Delegates the hello call to a remote object
-          using XML-RPC.
-
-          """
-          s = xmlrpclib.Server('http://www.zope.org/')
-          return s.hello(name)
-
-This component contacts a remote server and gets its hello greeting
-from a remote component.
-
-And that's all there is to components, really.  The rest of this
-chapter describes interfaces and how you can work with them from the
-perspective of components.  In Chapter 3, we'll put all this together
-into a Zope product.
-
-Python Interfaces
-=================
-
-Interface describe the behavior of an object by containing useful
-information about the object.  This information includes:
-
-- Prose documentation about the object.  In Python terms, this is
-  called the "doc string" of the interface.  In this element, you
-  describe how the object works in prose language and any other
-  useful information about the object.
-
-- Descriptions of attributes.  Attribute descriptions include the
-  name of the attribute and prose documentation describing the
-  attributes usage.
-
-- Descriptions of methods.  Method descriptions can include:
-
-  - Prose "doc string" documentation about the method and its usage.
-
-  - A sequence of parameter objects that describes the parameters
-    expected by the method.
-
-- Optional tagged data.  Interface objects (and their attributes,
-  methods, and method parameters) can have optional, application
-  specific tagged data associated with them.  Examples uses for this
-  are security assertions, pre/post conditions, unit tests, and other
-  possible information you may want to associate with an Interface or
-  its attributes.
-
-Not all of this information is mandatory.  For example, you may only
-want the methods of your interface to have prose documentation and
-not describe the arguments of the method in exact detail.  Interface
-objects are flexible and let you give or take any of these
-components.
-
-Why Use Interfaces?
-===================
-
-Interfaces solve a number of problems that arise while developing
-large systems with lots of developers.
-
-- Developers waste a lot of time looking at the source code of your
-  system to figure out how objects work.  This is even worse if
-  someone else has already wasted their time doing the same thing.
-
-- Developers who are new to your system may misunderstand how your
-  object works, causing, and possibly propagating, usage errors.
-
-- Because an object's interface is inferred from the source,
-  developers may end up using methods and attributes that are meant
-  for "internal use only".
-
-- Code inspection can be hard, and very discouraging to novice
-  programmers trying to understand code written by gurus.
-
-Interfaces try to solve these problems by providing a way for you to
-describe how to use an object, and a mechanism for discovering that
-description.
-
-Creating Interfaces                                       
-===================
-
-The first step to creating a component, as you've been shown, is to
-create an interface.
-
-Interface objects can be conveniently constructed using the Python
-``class`` statement.  Keep in mind that this syntax can be a little
-misleading, because interfaces are *not* classes.  It is important to
-understand that using Python's class syntax is just a convenience,
-and that the resulting object is an *interface*, not a class.
-
-To create an interface object using Python's class syntax, create a
-Python class that subclasses from ``zope.interface.Interface``::
-
-  from zope.interface import Interface
-
-  class IHello(Interface):
-
-      def hello(name):
-          """Say hello to the world"""
-
-This interface does not implement behavior for its methods, it just
-describes an interface that a typical "Hello" object would realize.
-By subclassing the ``zope.interface.Interface`` interface, the
-resulting object ``Hello`` is an interface object. The Python
-interpreter confirms this::
-
-  >>> IHello
-  <InterfaceClass __main__.IHello>
-
-Now, you can associate the ``Hello`` Interface with your new concrete
-class in which you define your user behavior.  For example::
-
-  class HelloComponent:
-
-      implements(IHello)
-
-      def hello(self, name):
-          return "Hello %s!" % name
-
-This new class, ``HelloComponent`` is a concrete class that
-implements the ``Hello`` interface.  A class can realize more than
-one interface.  For example, say you had an interface called 'Item'
-that described how an object worked as an item in a "Container"
-object.  If you wanted to assert that ``HelloComponent`` instances
-realized the ``Item`` interface as well as ``Hello``, you can provide
-a sequence of Interface objects to the 'HelloComponent' class::
-
-  class HelloComponent:
-
-      implements(IHello, IItem)
-
-
-The Interface Model
-===================
-
-Interfaces can extend other interfaces.  For example, let's extend
-the ``IHello`` interface by adding an additional method::
-
-  class ISmartHello(IHello):
-      """A Hello object that remembers who it's greeted"""
-
-      def lastGreeted(self):
-          """Returns the name of the last person greeted."""
-
-
-``ISmartHello`` extends the ``IHello`` interface.  It does this by
-using the same syntax a class would use to subclass another class.
-
-Now, you can ask the ``ISmartHello`` for a list of the interfaces it
-extends with ``getBases``::
-
-  >>> ISmartHello.getBases()
-  (<InterfaceClass __main__.IHello>,)
-
-An interface can extend any number of other interfaces, and
-``getBases`` will return that list of interfaces for you.  If you
-want to know if ``ISmartHello`` extends any other interface, you
-could call ``getBases`` and search through the list, but a
-convenience method called ``extends`` is provided that returns true
-or false for this purpose::
-
-  >>> ISmartHello.extends(IHello)
-  True
-  >>> ISandwich(Interface):
-  ...     pass
-  >>> ISmartHello.extends(ISandwich)
-  False
-
-Here you can see ``extends`` can be used to determine if one
-interface extends another.
-
-You may notice a similarity between interfaces extending from other
-interfaces and classes sub-classing from other classes.  This *is* a
-similar concept, but the two should not be considered equal.  There
-is no assumption that classes and interfaces exist in a one to one
-relationship; one class may implement several interfaces, and a class
-may not implement its base classes's interfaces.
-
-The distinction between a class and an interface should always be
-kept clear.  The purpose of a class is to share the implementation of
-how an object works.  The purpose of an interface is to document how
-to work *with* an object, not how the object is implemented.  It is
-possible to have several different classes with very different
-implementations realize the same interface.  Because of this,
-interfaces and classes should never be confused.
-
-
-Querying an Interface
-=====================
-
-Interfaces can be queried for information.  The simplest case is to
-ask an interface the names of all the various interface items it
-describes.  From the Python interpreter, for example, you can walk
-right up to an interface and ask it for its *names*::
-
-  >>> User.names()
-  ['getUserName', 'getFavoriteColor', 'getPassword']
-
-Interfaces can also give you more interesting information about their
-items.  Interface objects can return a list of '(name, description)'
-tuples about their items by calling the *namesAndDescriptions*
-method.
-
-For example::
-
-  >>> User.namesAndDescriptions()
-  [('getUserName', <Interface.Method.Method object at 80f38f0>),
-  ('getFavoriteColor', <Interface.Method.Method object at 80b24f0>),
-  ('getPassword', <Interface.Method.Method object at 80fded8>)]
-
-As you can see, the "description" of the Interface's three items in
-these cases are all `Method` objects.  Description objects can be
-either 'Attribute' or `Method` objects.  Attributes, methods, and
-interface objects implement the following interface::
-
-- `getName()` -- Returns the name of the object.
-
-- `getDoc()` -- Returns the documentation for the object.
-
-Method objects provide a way to describe rich meta-data about Python
-methods. Method objects have the following methods:
-
-- `getSignatureInfo()` -- Returns a dictionary describing the method
-  parameters.
-
-- `getSignatureString()` -- Returns a human-readable string
-  representation of the method's signature.
-
-For example::
-
-  >>> m = User.namesAndDescriptions()[0][1]
-  >>> m
-  <Interface.Method.Method object at 80f38f0>
-  >>> m.getSignatureString()
-  '(fullName=1)'
-  >>> m.getSignatureInfo()   
-  {'varargs': None, 'kwargs': None, 'optional': {'fullName': 1}, 
-  'required': (), 'positional': ('fullName',)}  
-
-You can use `getSignatureInfo` to find out the names and types of the
-method parameters.
-
-
-Checking Implementation
-=======================
-
-You can ask an interface if a certain class or instance that you hand
-it implements that interface.  For example, say you want to know if
-instances of the `HelloComponent` class implement 'Hello'::
-
-  IHello.implementedBy(HelloComponent)
-
-This is a true expression.  If you had an instance of
-`HelloComponent`, you can also ask the interface if that instance
-implements the interface::
-
-  IHello.implementedBy(my_hello_instance)
-
-This would also return true if *my_hello_instance* was an instance of
-*HelloComponent*, or any other class that implemented the *Hello*
-Interface.
-
-Conclusion
-==========
-
-Interfaces provide a simple way to describe your Python objects.  By
-using interfaces you document capabilities of objects.  As Zope
-becomes more component oriented, your objects will fit right in.
-While components and interfaces are forward looking technologies,
-they are useful today for documentation and verification.

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/Credits.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/Credits.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/Credits.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,13 +0,0 @@
-#######
-Credits
-#######
-
-- Amos Latteier
-
-- Michel Pelletier
-
-- Shane Hathaway
-
-- Chris McDonough
-
-- Beehive

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/GettingStarted.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/GettingStarted.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/GettingStarted.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,372 +0,0 @@
-###############
-Getting Started
-###############
-
-Introduction
-============
-
-This chapter cover installation and getting started with development
-of a simple application.  This guide use a build system called
-`Buildout <http://www.buildout.org>`_ to build the application.  And
-the Python packages developed as part of the application can be
-distributed as `Python eggs
-<http://peak.telecommunity.com/DevCenter/setuptools>`_.
-
-
-Directory Structure
-===================
-
-To begin the application development, create a directory structure to
-place Python packages and build related files.
-
-::
-
-  $ mkdir poll
-  $ mkdir poll/poll_build
-  $ mkdir poll/poll.main
-
-All build related files can be added inside `poll_build` directory.
-The main Python package can be added inside `poll.main` directory.
-We can make the ``poll``, a namespace package using the functionality
-provided by `pkg_resources` module included in setuptools.
-
-Bootstraping the Build
-======================
-
-You should have Python 2.5 or 2.6 installed in your system.  To start
-the build process, download and run `bootstrap.py`.  The
-`bootstrap.py` will download and install `setuptools` and
-`zc.buildout` packages.  Also it will create the directory structure
-and `buildout` script inside `bin` directory.
-
-::
-
-  $ cd poll/poll.build
-  $ touch buildout.cfg
-  $ wget -c http://svn.zope.org/repos/main/zc.buildout/trunk/bootstrap/bootstrap.py
-  $ python2.6 bootstrap.py
-
-Installing Zope 2
-=================
-
-From Zope 2.12 onwards Zope 2 is distributed in egg format.  To
-install Zope 2 egg and create an instance, update buildout
-configuration file (``buildout.cfg``) with appropriate parts and
-recipes.
-
-::
-
-  [buildout]
-  parts = zope2
-          instance
-  extends = http://download.zope.org/Zope2/index/2.12.0/versions.cfg
-
-  [zope2]
-  recipe = zc.recipe.egg
-  eggs = Zope2
-  interpreter = zopepy
-
-  [instance]
-  recipe = plone.recipe.zope2instance
-  user = admin:admin
-  http-address = 8080
-  eggs = ${zope2:eggs}
-
-The ``[zope2]`` part use `zc.recipe.egg` which will download `Zope2`
-egg and all its dependencies.  It will create few console scripts
-inside `bin` directory.  Also it will create a custom Python
-interpreter named ``zopepy``.
-
-The ``[instance]`` part creates a Zope 2 application instance to
-develop application.  It will create a script named ``instance``
-inside `bin` directory.  We can use that script to run the
-application instance.
-
-After updating the buildout configuration, you can run the `buildout`
-command to build the system.
-
-::
-
-  $ ./bin/buildout
-
-The initial build will take some time to complete.
-
-Running Instance
-================
-
-Once build is completed, you can run Zope 2 instance like this.
-
-::
-
-  $ ./bin/instance fg
-
-
-You can see that Zope is running in 8080 port.  You can go to the
-Zope Management Interface (ZMI).
-
-::
-
-  http://localhost:8080/manage
-
-You can provide the user name & password provided in `[instance]`
-part to access this page.
-
-You can see a list of installable applications in the drop-down box.
-Also you can see it in "Control_Panel" -> "Products".
-
-::
-
-  http://localhost:8080/Control_Panel/Products/manage_main
-
-In the next section we will make the `poll.main` listed here.  And
-later we will make it installable.
-
-
-Developing the main package
-===========================
-
-Now we can move to `poll.main` packae to create the main package to
-develop the application.  We can develop the entire application
-inside `poll.main` package.  But it is reccomended to split packages
-logically and maintain the dependencies between packages properly.
-
-::
-
-  $ cd ../poll.build
-
-Again we need to create the basic directory structure and `setup.py`
-to create egg distribution.  We are going to place python package
-inside `src` directory.
-
-::
-
-  $ touch setup.py
-  $ mkdir src
-  $ mkdir src/poll
-  $ mkdir src/poll/main
-  $ touch src/poll/__init__.py
-  $ touch src/poll/main/__init__.py
-  $ touch src/poll/main/configure.zcml
-
-The last file we created is a configuration file called Zope
-Configuration Markup Language (ZCML). Soon we will add some boiler
-plate code inside ZCML file.
-
-To declare `poll` as a namespace package, we need to add this boiler
-plate code to `src/poll/__init__.py`.
-
-::
-
-  __import__('pkg_resources').declare_namespace(__name__)
-
-Next we need to add the minimum meta data required for the package in
-`setup.py`.
-
-::
-
-  from setuptools import setup, find_packages
-
-  setup(
-      name="poll.main",
-      version="0.1",
-      packages=find_packages("src"),
-      package_dir={"": "src"},
-      namespace_packages=["poll"],
-      install_requires=["setuptools",
-                        "Zope2"],
-      )
-
-We need to add two more files to be recognized by Zope.  First,
-define this call-back function in `src/poll/main/__init__.py`.
-
-::
-
-  def initialize(registrar):
-      pass
-
-And in the ZCML file add these few lines.
-
-::
-
-  <configure
-      xmlns="http://namespaces.zope.org/five">
-
-      <registerPackage package="." initialize=".initialize" />
-
-  </configure>
-
-Creating Installable Application
-================================
-
-We need three things to make an installable application.
-
-- Form object created using ZPT (manage_addPollMain)
-- A function to define form action (addPollMain)
-- A class to define toplevel application object (PollMain).
-
-And we need to register the class along with form and add function
-using the `registrar` object passed to the `initialize` function.
-
-We can define all these things in `app.py` and the form template as
-`manage_addPollMain_form.zpt`.
-
-::
-
-  $ touch src/poll/main/app.py
-  $ touch src/poll/main/manage_addPollMain_form.zpt
-
-Here is the code for `app.py`.
-
-::
-
-  from OFS.Folder import Folder
-  from Products.PageTemplates.PageTemplateFile import PageTemplateFile
-
-  class PollMain(Folder):
-      meta_type = "POLL"
-
-  manage_addPollMain = PageTemplateFile("manage_addPollMain_form", globals())
-
-  def addPollMain(context, id):
-      """ """
-      context._setObject(id, PollMain(id))
-      return "POLL Installed: %s" % id
-
-And `manage_addPollMain_form.zpt`.
-
-::
-
-  <html xmlns="http://www.w3.org/1999/xhtml"
-        xmlns:tal="http://xml.zope.org/namespaces/tal">
-    <body>
-
-      <h2>Add POLL</h2>
-      <form action="addPollMain" method="post">
-        Id: <input type="text" name="id" /><br />
-        Title: <input type="text" name="title" /><br />
-        <input type="submit" value="Add" />
-      </form>
-    </body>
-  </html>
-
-Finally we can register it like this (update `__init__.py`)::
-
-  from poll.main.app import PollMain, manage_addPollMain, addPollMain
-
-  def initialize(registrar):
-      registrar.registerClass(PollMain,
-                              constructors=(manage_addPollMain, addPollMain))
-
-The application is now ready to install.  But we need to make some
-changes in `poll_build` to recognize this package by Zope 2.
-
-Adding poll.main to build
-=========================
-
-First in `[buildout]` part we need to mention that `poll.main` is
-locally developed.  Otherwise buildout will try to get the package
-from package index server, by default http://pypi.python.org/pypi .
-
-::
-
-  [buildout]
-  develop = ../poll.main
-  ...
-
-Also we need to add `poll.main` egg to `eggs` option in `[zope2]`
-part.
-
-::
-
-  ...
-  eggs = Zope2
-         poll.main
-  ...
-
-And finally we need to add a new option to include the ZCML file.  So
-that the package will be recognized by Zope.
-
-::
-
-  ...
-  zcml = poll.main
-
-The final `buildout.cfg` will look like this.
-
-::
-
-  [buildout]
-  develop = ../poll.main
-  parts = zope2
-          instance
-
-  [zope2]
-  recipe = zc.recipe.egg
-  eggs = Zope2
-         poll.main
-  interpreter = zopepy
-
-  [instance]
-  recipe = plone.recipe.zope2instance
-  user = admin:admin
-  http-address = 8080
-  eggs = ${zope2:eggs}
-  zcml = poll.main
-
-Now to make these change effective, run the buildout again.
-
-::
-
-  $ ./bin/buildout
-
-Now we can run application instance again.
-
-::
-
-  $ ./bin/instance fg
-
-Adding application instance
-===========================
-
-Visit ZMI and select `POLL` from the drop-down box.  It will display
-the add-form created earlier.  You can provide the ID as `poll` and
-submit the form.  After submitting, it should display a message:
-"POLL Installed: poll".
-
-Adding the main page to POLL
-============================
-
-In this section we will try to add a main page to POLL application.
-So that we can acces POLL application like this:
-http://localhost:8080/poll .
-
-First create a file named `index_html.zpt` inside `src/poll/main` with
-content like this::
-
-  <html>
-  <head>
-    <title>Welcome to POLL!</title>
-  </head>
-  <body>
-
-  <h2>Welcome to POLL!</h2>
-
-  </body>
-  </html>
-
-Now add an attribute named `index_html` inside PollMain class like
-this::
-
-  class PollMain(Folder):
-      meta_type = "POLL"
-
-      index_html = PageTemplateFile("index_html", globals())
-
-Restart the Zope. Now you can see that it display the main page when
-you access: http://localhost:8080/poll .
-
-Summary
-=======
-
-This chapter covered installation and beginning a simple project in
-Zope 2.

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/Introduction.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/Introduction.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/Introduction.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,97 +0,0 @@
-############
-Introduction
-############
-
-Overview
-========
-
-Zope 2 is a free and open-source, object-oriented web application
-server written in the Python programming language.  The term ZOPE is
-an acronym for "Z Object Publishing Environment" (the Z doesn't
-really mean anything in particular).  However, nowadays ZOPE is
-simply written as Zope.  It has three distinct audiences.
-
-*Site Managers*
-  Individuals who use of Zope's "out of the box" features to build
-  websites.  This audience is interested in making use of Zope's
-  existing array of features to create content management solutions.
-  They will likely make heavy use of "through the web" scripting
-  using DTML, Page Templates, and Python Scripts as well as (of
-  course) HTML and XML.  They are generally less concerned about code
-  reuse than the speed with which they can create a custom
-  application or website.
-
-*Developers*
-  Individuals who wish to extend Zope to create highly customized
-  solutions.  This audience is likely interested in creating highly
-  reusable custom code that makes Zope do something new and
-  interesting.  They will likely make heavy use of "through the
-  file-system" style development.
-
-*Administrators*
-  Individuals responsible for keeping a Zope site running and
-  performing installations and upgrades.
-
-This guide is intended to document Zope for the second audience,
-Developers, as defined above.  If you fit more into the "user"
-audience defined above, you'll probably want to start by reading `The
-Zope Book <http://docs.zope.org/zope2book>`_ .  If you fit more into
-the "administrator" audience defined above, you'll likely be
-interested in `The Zope Administrator's Guide
-<http://www.zope.org/DocProjects/AdminGuide>`_, although it is
-currently unfinished.
-
-Throughout this guide, it is assumed that you know how to program in
-the Python programming language.  Most of the examples in this guide
-will be in Python.  There are a number of great resources and books
-for learning Python; the best online resource is the `python.org web
-site <http://www.python.org/>`_ and many books can be found on the
-shelves of your local bookstore.
-
-Organization of the book
-========================
-
-This book describes Zope's services to the developer from a hands on,
-example-oriented standpoint.  This book is not a complete reference
-to the Zope API, but rather a practical guide to applying Zope's
-services to develop and deploy your own web applications.  This book
-covers the following topics:
-
-*Getting Started*
-  This chapter provides a brief overview of installation and getting
-  started with application development.
-
-*Components and Interfaces*
-  Zope use a component-centric development model.  This chapter
-  describes the component model in Zope and how Zope components are
-  described through interfaces.
-
-*Object Publishing*
-  Developing applications for Zope involves more than just creating a
-  component, that component must be *publishable* on the web.  This
-  chapter describes publication, and how your components need to be
-  designed to be published.
-
-*Zope Products*
-  New Zope components are distributed and installed in packages
-  called "Products".  This chapter explains Products in detail.
-
-*Persistent Components*
-  Zope provides a built-in, transparent Python object database called
-  ZODB.  This chapter describes how to create persistent components,
-  and how they work in conjunction with the ZODB.
-
-*Acquisition*
-  Zope relies heavily on a dynamic technique called acquisition. This
-  chapter explores acquisition thoroughly.
-
-*Security*
-  When your component is used by many different people through the
-  web, security becomes a big concern.  This chapter describes Zope's
-  security API and how you can use it to make security assertions
-  about your object.
-
-*Debugging and Testing*
-  Zope has built in debugging and testing support.  This chapter
-  describes these facilities and how you can debug and test your
-  components.

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/ObjectPublishing.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/ObjectPublishing.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/ObjectPublishing.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,1297 +0,0 @@
-#################
-Object Publishing
-#################
-
-Introduction
-============
-
-Zope puts your objects on the web. This is called *object
-publishing*. One of Zope's unique characteristics is the way it
-allows you to walk up to your objects and call methods on them with
-simple URLs.  In addition to HTTP, Zope makes your objects available
-to other network protocols including FTP, WebDAV and XML-RPC.
-
-
-In this chapter you'll find out exactly how Zope publishes
-objects. You'll learn all you need to know in order to design your
-objects for web publishing.
-
- 
-HTTP Publishing
-===============
-
-When you contact Zope with a web browser, your browser sends an HTTP
-request to Zope's web server. After the request is completely
-received, it is processed by 'ZPublisher', which is Zope's object
-publisher. 'ZPublisher' is a kind of light-weight ORB (Object Request
-Broker). It takes the request and locates an object to handle the
-request. The publisher uses the request URL as a map to locate the
-published object. Finding an object to handle the request is called
-*traversal*, since the publisher moves from object to object as it
-looks for the right one. Once the published object is found, the
-publisher calls a method on the published object, passing it
-parameters as necessary.  The publisher uses information in the
-request to determine which method to call, and what parameters to
-pass. The process of extracting parameters from the request is called
-*argument marshalling*. The published object then returns a response,
-which is passed back to Zope's web server. The web server, then
-passes the response back to your web browser.
-
-
-The publishing process is summarized in [2-1]
-
-.. figure:: ../Figures/2-1.png
-
-   2.1 Object publishing
-
-
-Typically the published object is a persistent object that the
-published module loads from the ZODB.  See Chapter 4 for more
-information on the ZODB.
-
-
-This chapter will cover all the steps of object publishing in
-detail. To summarize, object publishing consists of the main steps:
-
-1. The client sends a request to the publisher
-
-2. The publisher locates the published object using the request
-   URL as a map.
-
-3. The publisher calls the published object with arguments from
-   the request.
-
-4. The publisher interprets and returns the results to the
-   client.
-
-The chapter will also cover all the technical details, special cases
-and extra-steps that this list glosses over.
-
-
-URL Traversal
-=============
-
-Traversal is the process the publisher uses to locate the published
-object. Typically the publisher locates the published object by
-walking along the URL. Take for example a collection of objects::
-
-      class Classification:
-          ...
-
-      class Animal:
-          ...
-
-          def screech(self, ...):
-              ...
-
-      vertebrates=Classification(...)
-      vertebrates.mammals=Classification(...)
-      vertebrates.reptiles=Classification(...)
-      vertebrates.mammals.monkey=Animal(...)
-      vertebrates.mammals.dog=Animal(...)
-      vertebrates.reptiles.lizard=Animal(...)
-
-
-This collection of objects forms an object hierarchy. Using Zope you
-can publish objects with URLs. For example, the URL
-'http://zope/vertebrates/mammals/monkey/screech', will traverse the
-object hierarchy, find the 'monkey' object and call its 'screech'
-method.
-
-.. figure:: ../Figures/2-2.png
-
-   2.2 Traversal path through an object hierarchy
-
-The publisher starts from the root object and takes each step in the
-URL as a key to locate the next object. It moves to the next object
-and continues to move from object to object using the URL as a guide.
-
-Typically the next object is a sub-object of the current object that
-is named by the path segment. So in the example above, when the
-publisher gets to the 'vertebrates' object, the next path segment is
-"mammals", and this tells the publisher to look for a sub-object of
-the current object with that name. Traversal stops when Zope comes to
-the end of the URL. If the final object is found, then it is
-published, otherwise an error is returned.
-
-
-Now let's take a more rigorous look at traversal.
-
-Traversal Interfaces
-====================
-
-Zope defines interfaces for publishable objects, and publishable
-modules.
-
-
-When you are developing for Zope you almost always use the 'Zope'
-package as your published module. However, if you are using
-'ZPublisher' outside of Zope you'll be interested in the published
-module interface.
-
-
-Publishable Object Requirements
-===============================
-
-Zope has few restrictions on publishable objects. The basic rule is
-that the object must have a doc string. This requirement goes for
-method objects too.
-
-Another requirement is that a publishable object must not have a name
-that begin with an underscore. These two restrictions are designed to
-keep private objects from being published.
-
-
-Finally, published objects cannot be Python module objects.
-
-Traversal Methods
-=================
-
-During traversal, 'ZPublisher' cuts the URL into path elements
-delimited by slashes, and uses each path element to traverse from the
-current object to the next object. 'ZPublisher' locates the next
-object in one of three ways:
-
-1. Using '__bobo_traverse__'
-
-2. Using 'getattr'
-
-3. Using dictionary access.
-
-First the publisher attempts to call the traversal hook method,
-'__bobo_traverse__'. If the current object has this method it is
-called with the request and the current path element. The method
-should return the next object or 'None' to indicate that a next
-object can't be found. You can also return a tuple of objects from
-'__bobo_traverse__' indicating a sequence of sub-objects. This allows
-you to add additional parent objects into the request. This is almost
-never necessary.
-
-
-Here's an example of how to use '__bobo_traverse__'::
-
-          def __bobo_traverse__(self, request, key):
-              # if there is a special cookie set, return special
-              # subobjects, otherwise return normal subobjects
-
-              if request.cookies.has_key('special'):
-                  # return a subobject from the special dict
-                  return self.special_subobjects.get(key, None)
-
-              # otherwise return a subobject from the normal dict
-              return self.normal_subobjects.get(key, None)
-
-
-This example shows how you can examine the request during the
-traversal process.
-
-If the current object does not define a '__bobo_traverse__'
-method, then the next object is searched for using 'getattr'.
-This locates sub-objects in the normal Python sense.
-
-If the next object can't be found with 'getattr', 'ZPublisher'
-calls on the current object as though it were a
-dictionary. Note: the path element will be a string, not an
-integer, so you cannot traverse sequences using index numbers
-in the URL.
-
-For example, suppose 'a' is the current object, and 'next' is
-the name of the path element. Here are the three things that
-'ZPublisher' will try in order to find the next object:
-
-  1. 'a.__bobo_traverse__("next")'
-
-  2. 'a.next'
-
-  3. 'a["next"]'
-
-
-Publishing Methods        
-==================
-
-Once the published object is located with traversal, Zope *publishes*
-it in one of three possible ways.
-
-- Calling the published object -- If the published object is a
-  function or method or other callable object, the publisher calls
-  it. Later in the chapter you'll find out how the publisher figures
-  out what arguments to pass when calling.
-
-- Calling the default method -- If the published object is not
-  callable, the publisher uses the default method. For HTTP 'GET' and
-  'POST' requests the default method is 'index_html'. For other HTTP
-  requests such as 'PUT' the publisher looks for a method named by
-  the HTTP method. So for an HTTP 'HEAD' request, the publisher would
-  call the 'HEAD' method on the published object.
-
-- Stringifying the published object -- If the published object isn't
-  callable, and doesn't have a default method, the publisher
-  publishes it using the Python 'str' function to turn it into a
-  string.
-
-
-After the response method has been determined and called, the
-publisher must interpret the results.
-
-Character Encodings for Responses
-=================================
-
-If the published method returns an object of type 'string', a plain
-8-bit character string, the publisher will use it directly as the
-body of the response.
-
-Things are different if the published method returns a unicode
-string, because the publisher has to apply some character
-encoding. The published method can choose which character encoding it
-uses by setting a 'Content-Type' response header which includes a
-'charset' property (setting response headers is explained later in
-this chapter). A common choice of character encoding is UTF-8. To
-cause the publisher to send unicode results as UTF-8 you need to set
-a 'Content-Type' header with the value 'text/html; charset=UTF-8'
-
-If the 'Content-Type' header does not include a charser property (or
-if this header has not been set by the published method) then the
-publisher will choose a default character encoding. Today this
-default is ISO-8859-1 (also known as Latin-1) for compatability with
-old versions of Zope which did not include Unicode support. At some
-time in the future this default is likely to change to UTF-8.
-
-HTTP Responses
-==============
-
-Normally the published method returns a string which is considered
-the body of the HTTP response. The response headers can be controlled
-by calling methods on the response object, which is described later
-in the chapter. Optionally, the published method can return a tuple
-with the title, and body of the response. In this case, the publisher
-returns an generated HTML page, with the first item of the tuple used
-for the HTML 'title' of the page, and the second item as the contents
-of the HTML 'body' tag. For example a response of::
-
-  ('response', 'the response')
-
-
-is turned into this HTML page::
-
-  <html>
-  <head><title>response</title></head>
-  <body>the response</body>
-  </html>
-
-Controlling Base HREF
-=====================
-
-When you publish an object that returns HTML relative links should
-allow you to navigate between methods. Consider this example::
-
-  class Example:
-      "example"
-
-      def one(self):
-          "method one"
-          return """<html>
-                    <head>
-                    <title>one</title>
-                    </head>
-                    <body>
-                    <a href="two">two</a> 
-                    </body>
-                    </html>"""
-
-      def two(self):
-          "method two"
-          return """<html>
-                    <head>
-                    <title>two</title>
-                    </head>
-                    <body>
-                    <a href="one">one</a> 
-                    </body>
-                    </html>"""
-
-
-However, the default method, 'index_html' presents a problem. Since
-you can access the 'index_html' method without specifying the method
-name in the URL, relative links returned by the 'index_html' method
-won't work right. For example::
-
-            class Example:
-                "example"
-
-                 def index_html(self):
-                    return """<html>
-                              <head>
-                              <title>one</title>
-                              </head>
-                              <body>
-                              <a href="one">one</a><br>
-                              <a href="two">two</a> 
-                              </body>
-                              </html>"""
-                 ...
-
-If you publish an instance of the 'Example' class with the URL
-'http://zope/example', then the relative link to method 'one' will be
-'http://zope/one', instead of the correct link,
-'http://zope/example/one'.
-
-
-Zope solves this problem for you by inserting a 'base' tag inside the
-'head' tag in the HTML output of 'index_html' method when it is
-accessed as the default method. You will probably never notice this,
-but if you see a mysterious 'base' tag in your HTML output, know you
-know where it came from. You can avoid this behavior by manually
-setting your own base with a 'base' tag in your 'index_html' method
-output.
-
-
-Response Headers
-----------------
-
-The publisher and the web server take care of setting response
-headers such as 'Content-Length' and 'Content-Type'. Later in
-the chapter you'll find out how to control these headers.
-Later you'll also find out how exceptions are used to set the
-HTTP response code.
-
-Pre-Traversal Hook
-------------------
-
-The pre-traversal hook allows your objects to take special action
-before they are traversed. This is useful for doing things like
-changing the request. Applications of this include special
-authentication controls, and virtual hosting support.
-
-If your object has a method named '__before_publishing_traverse__',
-the publisher will call it with the current object and the request,
-before traversing your object. Most often your method will change the
-request. The publisher ignores anything you return from the
-pre-traversal hook method.
-
-The 'ZPublisher.BeforeTraverse' module contains some functions that
-help you register pre-traversal callbacks. This allows you to perform
-fairly complex callbacks to multiple objects when a given object is
-about to be traversed.
-
-
-Traversal and Acquisition
--------------------------
-
-Acquisition affects traversal in several ways. See Chapter 5,
-"Acquisition" for more information on acquisition. The most obvious
-way in which acquisition affects traversal is in locating the next
-object in a path. As we discussed earlier, the next object during
-traversal is often found using 'getattr'. Since acquisition affects
-'getattr', it will affect traversal. The upshot is that when you are
-traversing objects that support implicit acquisition, you can use
-traversal to walk over acquired objects. Consider the object
-hierarchy rooted in 'fruit'::
-
-        from Acquisition import Implicit
-
-        class Node(Implicit):
-            ...
-
-        fruit=Node()
-        fruit.apple=Node()
-        fruit.orange=Node()
-        fruit.apple.strawberry=Node()
-        fruit.orange.banana=Node()
-
-When publishing these objects, acquisition can come into play. For
-example, consider the URL */fruit/apple/orange*. The publisher would
-traverse from 'fruit', to 'apple', and then using acquisition, it
-would traverse to 'orange'.
-
-Mixing acquisition and traversal can get complex. Consider the URL
-*/fruit/apple/orange/strawberry/banana*. This URL is functional but
-confusing. Here's an even more perverse but legal URL
-*/fruit/apple/orange/orange/apple/apple/banana*.
-
-
-In general you should limit yourself to constructing URLs which use
-acquisition to acquire along containment, rather than context
-lines. It's reasonable to publish an object or method that you
-acquire from your container, but it's probably a bad idea to publish
-an object or method that your acquire from outside your
-container. For example::
-
-        from Acquisition import Implicit
-
-        class Basket(Implicit):
-            ...
-            def numberOfItems(self):
-                "Returns the number of contained items"
-                ...
-
-        class Vegetable(Implicit):
-            ...
-            def texture(self):
-                "Returns the texture of the vegetable."
-
-        class Fruit(Implicit):
-            ...
-            def color(self):
-                "Returns the color of the fruit."
-
-         basket=Basket()
-         basket.apple=Fruit()
-         basket.carrot=Vegetable()
-
-The URL */basket/apple/numberOfItems* uses acquisition along
-containment lines to publish the 'numberOfItems' method (assuming
-that 'apple' doesn't have a 'numberOfItems' attribute). However, the
-URL */basket/carrot/apple/texture* uses acquisition to locate the
-'texture' method from the 'apple' object's context, rather than from
-its container. While this distinction may be obscure, the guiding
-idea is to keep URLs as simple as possible. By keeping acquisition
-simple and along containment lines your application increases in
-clarity, and decreases in fragility.
-
-
-A second usage of acquisition in traversal concerns the request. The
-publisher tries to make the request available to the published object
-via acquisition. It does this by wrapping the first object in an
-acquisition wrapper that allows it to acquire the request with the
-name 'REQUEST'. This means that you can normally acquire the request
-in the published object like so::
-
-        request=self.REQUEST # for implicit acquirers
-
-or like so::
-
-        request=self.aq_acquire('REQUEST') # for explicit acquirers
-
-Of course, this will not work if your objects do not support
-acquisition, or if any traversed objects have an attribute named
-'REQUEST'.
-
-Finally, acquisition has a totally different role in object
-publishing related to security which we'll examine next.
-
-Traversal and Security
-----------------------
-
-As the publisher moves from object to object during traversal it
-makes security checks. The current user must be authorized to access
-each object along the traversal path. The publisher controls access
-in a number of ways. For more information about Zope security, see
-Chapter 6, "Security".
-
-Basic Publisher Security
-------------------------
-
-The publisher imposes a few basic restrictions on traversable
-objects. These restrictions are the same of those for publishable
-objects. As previously stated, publishable objects must have doc
-strings and must not have names beginning with underscore.
-
-The following details are not important if you are using the Zope
-framework. However, if your are publishing your own modules, the rest
-of this section will be helpful.
-
-The publisher checks authorization by examining the '__roles__'
-attribute of each object as it performs traversal. If present, the
-'__roles__' attribute should be 'None' or a list of role names. If it
-is None, the object is considered public. Otherwise the access to the
-object requires validation.
-
-Some objects such as functions and methods do not support creating
-attributes (at least they didn't before Python 2). Consequently, if
-the object has no '__roles__' attribute, the publisher will look for
-an attribute on the object's parent with the name of the object
-followed by '__roles__'. For example, a function named 'getInfo'
-would store its roles in its parent's 'getInfo__roles__' attribute.
-
-If an object has a '__roles__' attribute that is not empty and not
-'None', the publisher tries to find a user database to authenticate
-the user. It searches for user databases by looking for an
-'__allow_groups__' attribute, first in the published object, then in
-the previously traversed object, and so on until a user database is
-found.
-
-When a user database is found, the publisher attempts to validate the
-user against the user database. If validation fails, then the
-publisher will continue searching for user databases until the user
-can be validated or until no more user databases can be found.
-
-The user database may be an object that provides a validate
-method::
-
-  validate(request, http_authorization, roles)
-
-where 'request' is a mapping object that contains request
-information, 'http_authorization' is the value of the HTTP
-'Authorization' header or 'None' if no authorization header was
-provided, and 'roles' is a list of user role names.
-
-The validate method returns a user object if succeeds, and 'None' if
-it cannot validate the user. See Chapter 6 for more information on
-user objects. Normally, if the validate method returns 'None', the
-publisher will try to use other user databases, however, a user
-database can prevent this by raising an exception.
-
-
-If validation fails, Zope will return an HTTP header that causes your
-browser to display a user name and password dialog. You can control
-the realm name used for basic authentication by providing a module
-variable named '__bobo_realm__'. Most web browsers display the realm
-name in the user name and password dialog box.
-
-If validation succeeds the publisher assigns the user object to the
-request variable, 'AUTHENTICATED_USER'. The publisher places no
-restriction on user objects.
-
-
-Zope Security
-
-When using Zope rather than publishing your own modules, the
-publisher uses acquisition to locate user folders and perform
-security checks. The upshot of this is that your published objects
-must inherit from 'Acquisition.Implicit' or
-'Acquisition.Explicit'. See Chapter 5, "Acquisition", for more
-information about these classes. Also when traversing each object
-must be returned in an acquisition context. This is done
-automatically when traversing via 'getattr', but you must wrap
-traversed objects manually when using '__getitem__' and
-'__bobo_traverse__'. For example::
-
-          class Example(Acquisition.Explicit):
-              ...
-
-              def __bobo_traverse__(self, name, request):
-                  ...
-                  next_object=self._get_next_object(name)
-                  return  next_object.__of__(self)      
-
-
-Finally, traversal security can be circumvented with the
-'__allow_access_to_unprotected_subobjects__' attribute as described
-in Chapter 6, "Security".
-
-
-Environment Variables
-=====================
-
-You can control some facets of the publisher's operation by setting
-environment variables.
-
-- 'Z_DEBUG_MODE' -- Sets debug mode. In debug mode tracebacks are not
-  hidden in error pages. Also debug mode causes 'DTMLFile' objects,
-  External Methods and help topics to reload their contents from disk
-  when changed. You can also set debug mode with the '-D' switch when
-  starting Zope.
-
-- 'Z_REALM' -- Sets the basic authorization realm. This controls the
-  realm name as it appears in the web browser's username and password
-  dialog. You can also set the realm with the '__bobo_realm__' module
-  variable, as mentioned previously.
-
-- 'PROFILE_PUBLISHER' -- Turns on profiling and sets the name of the
-  profile file. See the Python documentation for more information
-  about the Python profiler.
-
-
-Many more options can be set using switches on the startup
-script. See the *Zope Administrator's Guide* for more information.
-
-Testing
--------
-
-ZPublisher comes with built-in support for testing and working with
-the Python debugger.  This topic is covered in more detail in Chapter
-7, "Testing and Debugging".
-
-Publishable Module
-------------------
-
-If you are using the Zope framework, this section will be irrelevant
-to you. However, if you are publishing your own modules with
-'ZPublisher' read on.
-
-The publisher begins the traversal process by locating an object in
-the module's global namespace that corresponds to the first element
-of the path. Alternately the first object can be located by one of
-two hooks.
-
-If the module defines a 'web_objects' or 'bobo_application' object,
-the first object is searched for in those objects. The search happens
-according to the normal rules of traversal, using
-'__bobo_traverse__', 'getattr', and '__getitem__'.
-
-The module can receive callbacks before and after traversal. If the
-module defines a '__bobo_before__' object, it will be called with no
-arguments before traversal. Its return value is ignored. Likewise, if
-the module defines a '__bobo_after__' object, it will be called after
-traversal with no arguments. These callbacks can be used for things
-like acquiring and releasing locks.
-
-Calling the Published Object
-----------------------------
-
-Now that we've covered how the publisher located the published object
-and what it does with the results of calling it, let's take a closer
-look at how the published object is called.
-
-The publisher marshals arguments from the request and automatically
-makes them available to the published object. This allows you to
-accept parameters from web forms without having to parse the
-forms. Your objects usually don't have to do anything special to be
-called from the web. Consider this function::
-
-      def greet(name):
-          "greet someone"
-          return "Hello, %s" % name
-
-You can provide the 'name' argument to this function by calling it
-with a URL like *greet?name=World*. You can also call it with a HTTP
-'POST' request which includes 'name' as a form variable.
-
-In the next sections we'll take a closer look at how the publisher
-marshals arguments.
-
-Marshalling Arguments from the Request
---------------------------------------
-
-The publisher marshals form data from GET and POST requests. Simple
-form fields are made available as Python strings. Multiple fields
-such as form check boxes and multiple selection lists become
-sequences of strings. File upload fields are represented with
-'FileUpload' objects. File upload objects behave like normal Python
-file objects and additionally have a 'filename' attribute which is
-the name of the file and a 'headers' attribute which is a dictionary
-of file upload headers.
-
-The publisher also marshals arguments from CGI environment variables
-and cookies. When locating arguments, the publisher first looks in
-CGI environment variables, then other request variables, then form
-data, and finally cookies. Once a variable is found, no further
-searching is done. So for example, if your published object expects
-to be called with a form variable named 'SERVER_URL', it will fail,
-since this argument will be marshaled from the CGI environment first,
-before the form data.
-
-The publisher provides a number of additional special variables such
-as 'URL0' which are derived from the request. These are covered in
-the 'HTTPRequest' API documentation.
-
-Argument Conversion
--------------------
-
-The publisher supports argument conversion. For example consider this
-function::
-
-        def onethird(number):
-            "returns the number divided by three"
-            return number / 3.0
-
-This function cannot be called from the web because by default the
-publisher marshals arguments into strings, not numbers. This is why
-the publisher provides a number of converters. To signal an argument
-conversion you name your form variables with a colon followed by a
-type conversion code. For example, to call the above function with 66
-as the argument you can use this URL *onethird?number:int=66* The
-publisher supports many converters:
-
-- boolean -- Converts a variable to true or false. Variables that are
-  0, None, an empty string, or an empty sequence are false, all
-  others are true.
-
-- int -- Converts a variable to a Python integer.
-
-- long -- Converts a variable to a Python long integer.
-
-- float -- Converts a variable to a Python floating point number.
-
-- string -- Converts a variable to a Python string.
-
-- ustring -- Converts a variable to a Python unicode string.
-
-- required -- Raises an exception if the variable is not present or
-  is an empty string.
-
-- ignore_empty -- Excludes a variable from the request if the
-  variable is an empty string.
-
-- date -- Converts a string to a *DateTime* object. The formats
-  accepted are fairly flexible, for example '10/16/2000', '12:01:13
-  pm'.
-
-- list -- Converts a variable to a Python list of values, even if
-  there is only one value.
-
-- tuple -- Converts a variable to a Python tuple of values, even if
-  there is only one value.
-
-- lines -- Converts a string to a Python list of values by splitting
-  the string on line breaks.
-
-- tokens -- Converts a string to a Python list of values by splitting
-  the string on spaces.
-
-- text -- Converts a variable to a string with normalized line
-  breaks.  Different browsers on various platforms encode line
-  endings differently, so this converter makes sure the line endings
-  are consistent, regardless of how they were encoded by the browser.
-
-- ulines, utokens, utext -- like lines, tokens, text, but using
-  unicode strings instead of plain strings.
-
-If the publisher cannot coerce a request variable into the type
-required by the type converter it will raise an error. This is useful
-for simple applications, but restricts your ability to tailor error
-messages. If you wish to provide your own error messages, you should
-convert arguments manually in your published objects rather than
-relying on the publisher for coercion. Another possibility is to use
-JavaScript to validate input on the client-side before it is
-submitted to the server.
-
-You can combine type converters to a limited extent. For example you
-could create a list of integers like so::
-
-        <input type="checkbox" name="numbers:list:int" value="1">
-        <input type="checkbox" name="numbers:list:int" value="2">
-        <input type="checkbox" name="numbers:list:int" value="3">
-
-In addition to these type converters, the publisher also supports
-method and record arguments.
-
-Character Encodings for Arguments
----------------------------------
-
-The publisher needs to know what character encoding was used by the
-browser to encode form fields into the request. That depends on
-whether the form was submitted using GET or POST (which the publisher
-can work out for itself) and on the character encoding used by the
-page which contained the form (for which the publisher needs your
-help).
-
-In some cases you need to add a specification of the character
-encoding to each fields type converter. The full details of how this
-works are explained below, however most users do not need to deal
-with the full details:
-
-1. If your pages all use the UTF-8 character encoding (or at least
-   all the pages that contain forms) the browsers will always use
-   UTF-8 for arguments. You need to add ':utf8' into all argument
-   type converts. For example:
-
-   <input type="text" name="name:utf8:ustring">
-   <input type="checkbox" name="numbers:list:int:utf8" value="1">
-   <input type="checkbox" name="numbers:list:int:utf8" value="1">
-
-     % Anonymous User - Apr. 6, 2004 5:56 pm:
-      121
-
-2. If your pages all use a character encoding which has ASCII as a
-   subset (such as Latin-1, UTF-8, etc) then you do not need to
-   specify any chatacter encoding for boolean, int, long, float, and
-   date types.  You can also omit the character encoding type
-   converter from string, tokens, lines, and text types if you only
-   need to handle ASCII characters in that form field.
-
-Character Encodings for Arguments; The Full Story
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you are not in one of those two easy categories, you first need to
-determine which character encoding will be used by the browser to
-encode the arguments in submitted forms.
-
-1. Forms submitted using GET, or using POST with 
-   "application/x-www-form-urlencoded" (the default) 
-
-   1. Page uses an encoding of unicode: Forms are submitted using
-      UTF8, as required by RFC 2718 2.2.5
-
-   2. Page uses another regional 8 bit encoding: Forms are often
-      submitted using the same encoding as the page. If you choose to
-      use such an encoding then you should also verify how browsers
-      behave.
-
-2. Forms submitted using "multipart/form-data":
-
-   According to HTML 4.01 (section 17.13.4) browsers should state
-   which character encoding they are using for each field in a
-   Content-Type header, however this is poorly supported. The current
-   crop of browsers appear to use the same encoding as the page
-   containing the form.
-
-   Every field needs that character encoding name appended to is
-   converter.  The tag parser insists that tags must only use
-   alphanumberic characters or an underscore, so you might need to
-   use a short form of the encoding name from the Python 'encodings'
-   library package (such as utf8 rather than UTF-8).
-
-
-Method Arguments
-----------------
-
-Sometimes you may wish to control which object is published based on
-form data. For example, you might want to have a form with a select
-list that calls different methods depending on the item
-chosen. Similarly, you might want to have multiple submit buttons
-which invoke a different method for each button.
-
-The publisher provides a way to select methods using form variables
-through use of the *method* argument type. The method type allows the
-request 'PATH_INFO' to be augmented using information from a form
-item name or value.
-
-If the name of a form field is ':method', then the value of the field
-is added to 'PATH_INFO'. For example, if the original 'PATH_INFO' is
-'foo/bar' and the value of a ':method' field is 'x/y', then
-'PATH_INFO' is transformed to 'foo/bar/x/y'. This is useful when
-presenting a select list. Method names can be placed in the select
-option values.
-
-If the name of a form field ends in ':method' then the part of the
-name before ':method' is added to 'PATH_INFO'. For example, if the
-original 'PATH_INFO' is 'foo/bar' and there is a 'x/y:method' field,
-then 'PATH_INFO' is transformed to 'foo/bar/x/y'. In this case, the
-form value is ignored. This is useful for mapping submit buttons to
-methods, since submit button values are displayed and should,
-therefore, not contain method names.
-
-Only one method field should be provided. If more than one method
-field is included in the request, the behavior is undefined.
-
-Record Arguments 
-----------------
-
-Sometimes you may wish to consolidate form data into a structure
-rather than pass arguments individually. Record arguments allow you
-to do this.
-
-The 'record' type converter allows you to combine multiple
-form variables into a single input variable. For example::
-
-  <input name="date.year:record:int">
-  <input name="date.month:record:int">
-  <input name="date.day:record:int">
-
-This form will result in a single variable, 'date', with
-attributes 'year', 'month', and 'day'.
-
-You can skip empty record elements with the 'ignore_empty'
-converter. For example::
-
-  <input type="text" name="person.email:record:ignore_empty">
-
-When the email form field is left blank the publisher skips over the
-variable rather than returning a null string as its value. When the
-record 'person' is returned it will not have an 'email' attribute if
-the user did not enter one.
-
-You can also provide default values for record elements with the
-'default' converter. For example::
-
-  <input type="hidden"
-         name="pizza.toppings:record:list:default" 
-         value="All">
-  <select multiple name="pizza.toppings:record:list:ignore_empty">
-  <option>Cheese</option>
-  <option>Onions</option>
-  <option>Anchovies</option>
-  <option>Olives</option>
-  <option>Garlic<option>
-  </select>
-
-The 'default' type allows a specified value to be inserted when the
-form field is left blank. In the above example, if the user does not
-select values from the list of toppings, the default value will be
-used. The record 'pizza' will have the attribute 'toppings' and its
-value will be the list containing the word "All" (if the field is
-empty) or a list containing the selected toppings.
-
-You can even marshal large amounts of form data into multiple records
-with the 'records' type converter. Here's an example::
-
-  <h2>Member One</h2>
-  Name:
-  <input type="text" name="members.name:records"><BR>
-  Email:
-  <input type="text" name="members.email:records"><BR>
-  Age:
-  <input type="text" name="members.age:int:records"><BR>
-
-  <H2>Member Two</H2>
-  Name:
-  <input type="text" name="members.name:records"><BR>
-  Email:
-  <input type="text" name="members.email:records"><BR>
-  Age:
-  <input type="text" name="members.age:int:records"><BR>
-
-This form data will be marshaled into a list of records named
-'members'. Each record will have a 'name', 'email', and 'age'
-attribute.
-
-Record marshalling provides you with the ability to create complex
-forms. However, it is a good idea to keep your web interfaces as
-simple as possible.
-
-Exceptions
-----------
-
-Unhandled exceptions are caught by the object publisher and are
-translated automatically to nicely formatted HTTP output.
-
-When an exception is raised, the exception type is mapped to an HTTP
-code by matching the value of the exception type with a list of
-standard HTTP status names. Any exception types that do not match
-standard HTTP status names are mapped to "Internal Error" (500). The
-standard HTTP status names are: "OK", "Created", "Accepted", "No
-Content", "Multiple Choices", "Redirect", "Moved Permanently", "Moved
-Temporarily", "Not Modified", "Bad Request", "Unauthorized",
-"Forbidden", "Not Found", "Internal Error", "Not Implemented", "Bad
-Gateway", and "Service Unavailable". Variations on these names with
-different cases and without spaces are also valid.
-
-An attempt is made to use the exception value as the body of the
-returned response. The object publisher will examine the exception
-value. If the value is a string that contains some white space, then
-it will be used as the body of the return error message. If it
-appears to be HTML, the error content type will be set to
-'text/html', otherwise, it will be set to 'text/plain'. If the
-exception value is not a string containing white space, then the
-object publisher will generate its own error message.
-
-There are two exceptions to the above rule:
-
-1. If the exception type is: "Redirect", "Multiple Choices" "Moved
-   Permanently", "Moved Temporarily", or "Not Modified", and the
-   exception value is an absolute URI, then no body will be provided
-   and a 'Location' header will be included in the output with the
-   given URI.
-
-2. If the exception type is "No Content", then no body will be
-   returned.
-
-When a body is returned, traceback information will be included in a
-comment in the output. As mentioned earlier, the environment variable
-'Z_DEBUG_MODE' can be used to control how tracebacks are included. If
-this variable is set then tracebacks are included in 'PRE' tags,
-rather than in comments. This is very handy during debugging.
-
-Exceptions and Transactions
----------------------------
-
-When Zope receives a request it begins a transaction. Then it begins
-the process of traversal. Zope automatically commits the transaction
-after the published object is found and called. So normally each web
-request constitutes one transaction which Zope takes care of for
-you. See Chapter 4. for more information on transactions.
-
-If an unhandled exception is raised during the publishing process,
-Zope aborts the transaction. As detailed in Chapter
-4. Zope handles 'ConflictErrors' by re-trying the request up to
-three times.  This is done with the 'zpublisher_exception_hook'.
-
-In addition, the error hook is used to return an error message to the
-user. In Zope the error hook creates error messages by calling the
-'raise_standardErrorMessage' method. This method is implemented by
-'SimpleItem.Item'. It acquires the 'standard_error_message' DTML
-object, and calls it with information about the exception.
-
-You will almost never need to override the
-'raise_standardErrorMessage' method in your own classes, since it is
-only needed to handle errors that are raised by other components. For
-most errors, you can simply catch the exceptions normally in your
-code and log error messages as needed. If you need to, you should be
-able to customize application error reporting by overriding the
-'standard_error_message' DTML object in your application.
-
-Manual Access to Request and Response
--------------------------------------
-
-You do not need to access the request and response directly most of
-the time. In fact, it is a major design goal of the publisher that
-most of the time your objects need not even be aware that they are
-being published on the web. However, you have the ability to exert
-more precise control over reading the request and returning the
-response.
-
-Normally published objects access the request and response by listing
-them in the signature of the published method. If this is not
-possible you can usually use acquisition to get a reference to the
-request. Once you have the request, you can always get the response
-from the request like so::
-
-  response=REQUEST.RESPONSE
-
-The APIs of the request and response are covered in the API
-documentation. Here we'll look at a few common uses of the request
-and response.
-
-One reason to access the request is to get more precise information
-about form data. As we mentioned earlier, argument marshalling comes
-from a number of places including cookies, form data, and the CGI
-environment. For example, you can use the request to differentiate
-between form and cookie data::
-
-  cookies = REQUEST.cookies # a dictionary of cookie data
-  form = REQUEST.form # a dictionary of form data
-
-One common use of the response object is to set response headers.
-Normally the publisher in concert with the web server will take care
-of response headers for you. However, sometimes you may wish manually
-control headers::
-
-  RESPONSE.setHeader('Pragma', 'No-Cache')
-
-Another reason to access the response is to stream response data. You
-can do this with the 'write' method::
-
-  while 1:
-      data=getMoreData() #this call may block for a while
-      if not data:
-          break
-      RESPONSE.write(data)
-
-Here's a final example that shows how to detect if your method is
-being called from the web. Consider this function::
-
-  def feedParrot(parrot_id, REQUEST=None):
-      ...
-
-      if REQUEST is not None:
-          return "<html><p>Parrot %s fed</p></html>" % parrot_id
-
-The 'feedParrot' function can be called from Python, and also from
-the web. By including 'REQUEST=None' in the signature you can
-differentiate between being called from Python and being called form
-the web. When the function is called from Python nothing is returned,
-but when it is called from the web the function returns an HTML
-confirmation message.
-
-Other Network Protocols
-=======================
-
-FTP
----
-
-Zope comes with an FTP server which allows users to treat the Zope
-object hierarchy like a file server. As covered in Chapter 3, Zope
-comes with base classes ('SimpleItem' and 'ObjectManager') which
-provide simple FTP support for all Zope objects. The FTP API is
-covered in the API reference.
-
-To support FTP in your objects you'll need to find a way to represent
-your object's state as a file. This is not possible or reasonable for
-all types of objects. You should also consider what users will do
-with your objects once they access them via FTP.  You should find out
-which tools users are likely to edit your object files.  For example,
-XML may provide a good way to represent your object's state, but it
-may not be easily editable by your users.  Here's an example class
-that represents itself as a file using RFC 822 format::
-
-  from rfc822 import Message
-  from cStringIO import StringIO
-
-  class Person(...):
-
-      def __init__(self, name, email, age):
-          self.name=name
-          self.email=email
-          self.age=age
-
-      def writeState(self):
-          "Returns object state as a string"
-          return "Name: %s\nEmail: %s\nAge: %s" % (self.name,
-                                                   self.email, 
-                                                   self.age)
-      def readState(self, data):
-          "Sets object state given a string"
-          m=Message(StringIO(data))
-          self.name=m['name']
-          self.email=m['email']
-          self.age=int(m['age'])
-
-The 'writeState' and 'readState' methods serialize and unserialize
-the 'name', 'age', and 'email' attributes to and from a string. There
-are more efficient ways besides RFC 822 to store instance attributes
-in a file, however RFC 822 is a simple format for users to edit with
-text editors.
-
-To support FTP all you need to do at this point is implement the
-'manage_FTPget' and 'PUT' methods. For example::
-
-  def manage_FTPget(self):
-      "Returns state for FTP"
-      return self.writeState()
-
-  def PUT(self, REQUEST):
-      "Sets state from FTP"
-       self.readState(REQUEST['BODY'])
-
-You may also choose to implement a 'get_size' method which returns
-the size of the string returned by 'manage_FTPget'. This is only
-necessary if calling 'manage_FTPget' is expensive, and there is a
-more efficient way to get the size of the file. In the case of this
-example, there is no reason to implement a 'get_size' method.
-
-One side effect of implementing 'PUT' is that your object now
-supports HTTP PUT publishing. See the next section on WebDAV for more
-information on HTTP PUT.
-
-That's all there is to making your object work with FTP. As you'll
-see next WebDAV support is similar.
-
-WebDAV
-------
-
-WebDAV is a protocol for collaboratively edit and manage files on
-remote servers. It provides much the same functionality as FTP, but
-it works over HTTP.
-
-It is not difficult to implement WebDAV support for your
-objects. Like FTP, the most difficult part is to figure out how to
-represent your objects as files.
-
-Your class must inherit from 'webdav.Resource' to get basic DAV
-support. However, since 'SimpleItem' inherits from 'Resource', your
-class probably already inherits from 'Resource'. For container
-classes you must inherit from 'webdav.Collection'. However, since
-'ObjectManager' inherits from 'Collection' you are already set so
-long as you inherit from 'ObjectManager'.
-
-In addition to inheriting from basic DAV classes, your classes must
-implement 'PUT' and 'manage_FTPget'. These two methods are also
-required for FTP support. So by implementing WebDAV support, you also
-implement FTP support.
-
-The permissions that you assign to these two methods will control the
-ability to read and write to your class through WebDAV, but the
-ability to see your objects is controlled through the "WebDAV access"
-permission.
-
-Supporting Write Locking
-------------------------
-
-Write locking is a feature of WebDAV that allows users to put lock on
-objects they are working on. Support write locking s easy. To
-implement write locking you must assert that your lass implements the
-'WriteLockInterface'. For example::
-
-  from webdav.WriteLockInterface import WriteLockInterface
-
-  class MyContentClass(OFS.SimpleItem.Item, Persistent):
-      __implements__ = (WriteLockInterface,)
-
-It's sufficient to inherit from 'SimpleItem.Item', since it inherits
-from 'webdav.Resource', which provides write locking long with other
-DAV support.
-
-In addition, your 'PUT' method should begin with calls to dav__init'
-and 'dav_simpleifhandler'. For example::
-
- def PUT(self, REQUEST, RESPONSE):
-     """
-     Implement WebDAV/HTTP PUT/FTP put method for this object.
-     """
-     self.dav__init(REQUEST, RESPONSE)
-     self.dav__simpleifhandler(REQUEST, RESPONSE)
-     ...
-
-Finally your class's edit methods should check to determine whether
-your object is locked using the 'ws_isLocked' method. If someone
-attempts to change your object when it is locked you should raise the
-'ResourceLockedError'. For example::
-
-  from webdav import ResourceLockedError
-
-  class MyContentClass(...):
-      ...
-
-      def edit(self, ...):
-          if self.ws_isLocked():
-              raise ResourceLockedError
-          ...
-
-WebDAV support is not difficult to implement, and as more WebDAV
-editors become available, it will become more valuable. If you choose
-to add FTP support to your class you should probably go ahead and
-support WebDAV too since it is so easy once you've added FTP support.
-
-XML-RPC
--------
-
-`XML-RPC <http://www.xmlrpc.com>`_ is a light-weight Remote Procedure
-Call protocol that uses XML for encoding and HTTP for
-transport. Fredrick Lund maintains a Python <XML-RPC module
-<http://www.pythonware.com/products/xmlrpc>`_ .
-
-All objects in Zope support XML-RPC publishing. Generally you will
-select a published object as the end-point and select one of its
-methods as the method. For example you can call the 'getId' method on
-a Zope folder at 'http://example.com/myfolder' like so::
-
-  import xmlrpclib
-  folder = xmlrpclib.Server('http://example.com/myfolder')
-  ids = folder.getId()
-
-You can also do traversal via a dotted method name. For example::
-
-  import xmlrpclib
-
-  # traversal via dotted method name
-  app = xmlrpclib.Server('http://example.com/app')
-  id1 = app.folderA.folderB.getId()
-
-  # walking directly up to the published object
-  folderB = xmlrpclib.Server('http://example.com/app/folderA/folderB')
-  id2 = folderB.getId()
-
-  print id1 == id2
-
-This example shows different routes to the same object publishing
-call.
-
-XML-RPC supports marshalling of basic Python types for both
-publishing requests and responses. The upshot of this arrangement is
-that when you are designing methods for use via XML-RPC you should
-limit your arguments and return values to simple values such as
-Python strings, lists, numbers and dictionaries. You should not
-accept or return Zope objects from methods that will be called via
-XML-RPC.
-
-
-XML-RPC does not support keyword arguments. This is a problem if your
-method expect keyword arguments.  This problem is noticeable when
-calling DTMLMethods and DTMLDocuments with XML-RPC.  Normally a DTML
-object should be called with the request as the first argument, and
-additional variables as keyword arguments.  You can get around this
-problem by passing a dictionary as the first argument. This will
-allow your DTML methods and documents to reference your variables
-with the 'var' tag.  However, you cannot do the following::
-
-  <dtml-var expr="REQUEST['argument']">
-
-Although the following will work::
-
-  <dtml-var expr="_['argument']">
-
-This is because in this case arguments *are* in the DTML namespace,
-but they are not coming from the web request.
-
-In general it is not a good idea to call DTML from XML-RPC since DTML
-usually expects to be called from normal HTTP requests.
-
-One thing to be aware of is that Zope returns 'false' for published
-objects which return None since XML-RPC has no concept of null.
-
-Another issue you may run into is that 'xmlrpclib' does not yet
-support HTTP basic authentication. This makes it difficult to call
-protected web resources. One solution is to patch
-'xmlrpclib'. Another solution is to accept authentication credentials
-in the signature of your published method.
-
-Summary
-=======
-
-Object publishing is a simple and powerful way to bring objects to
-the web. Two of Zope's most appealing qualities is how it maps
-objects to URLs, and you don't need to concern yourself with web
-plumbing. If you wish, there are quite a few details that you can use
-to customize how your objects are located and published.
-

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/Outline.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/Outline.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/Outline.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,159 +0,0 @@
-#######
-Outline
-#######
-
-Covers audience, topic, and scope.  Gives brief description of the
-developers guide and what goals the guide tries to acomplish.  Gives
-simple chapter by chapter overview of entire guide.
-
-
-Interfaces
-==========
-
-Zope is moving toward a more "self-documenting" model, where Zope
-component describe themselves with interfaces.  Many of the prose
-descriptions and examples in this guide will be working with these
-kinds of components.  This chapter gives a brief overview of Zope
-interfaces, how they describe Zope components, and how developers can
-create their own interfaces.
-
-This section is meant to enable the reader to discover the Zope "API"
-for themselves.  One of the goals of this guide is *not* to be an
-exhaustive descrption of the Zope API, that can be found in the
-online help system and from Zope objects through their interfaces.
-
-The majority of the content of this chapter will come from the
-`Interface documentation
-<http://www.zope.org/Wikis/Interfaces/InterfaceUserDocumentation>`_
-
-1. What are interfaces, why are they useful?
-
-2. Reading interfaces
-
-3. Using and testing interfaces
-
-4. Defining interfaces
-
-
-Publishing
-==========
-
-One key facility that Zope provides for a component developer is
-access to a component through various network protocols, like HTTP.
-While a component can be designed to work exclusivly with other
-components through Python only interfaces, most components are
-designed to be used and managed through a network interface, most
-commonly HTTP.
-
-Zope provides network access to components by "publishing" them
-through various network interfaces like HTTP, FTP, WebDAV and
-XML-RPC.  This chapter describes how a component developer can
-publish their components "through the web" and other network
-protocols.
-
-1. Object publishing overview
-
-2. Traversal
-
-3. Network Protocols
-
-4. Publishable Interfaces
-
-5. Object marshalling
-
-6. Creating user interfaces
-
-   - with DTMLFile
-
-   - with presentation templates
-
-
-Products
-========
-
-Zope defines a system that allows component developers to distribute
-their components to other Zope users.  Components can be placed into
-a package called a "Product".  Products can be created either through
-the web, or in Python.  Through the web products are covered in *The
-Zope Book*, and this chapter describes the more advanced Python
-product interfaces that developers can use to distribute their
-Python-based components.
-
-The majority of the content of this chapter will come from
-Amos/Shane's `Product Tutorial
-<http://www.zope.org/Members/hathawsh/PythonProductTutorial>`_
-
-1. Introduction
-
-2. Development Process
-
-3. Product Architecture
-
-4. Building Product Classes
-
-5. Building Management Interfaces
-
-6. Packaging Products
-
-7. Evolving Products
-
-
-Persistence
-===========
-
-Most Zope components live in the Zope Object DataBase (ZODB).
-Components that are stored in ZODB are called *persistent*.  Creating
-persistent components is, for the most part, a trivial exercise, but
-ZODB does impose a few rules that persistent components must obey in
-oder to work properly.  This chapter describes the persistent model
-and the interfaces that persistent objects can use to live inside the
-ZODB.
-
-1. Persistence Architecture
-
-2. Using Persistent components
-
-3. Creating Persistent Objects
-
-4. Transactions
-
-
-Security
-========
-
-Zope has a very fine-grained, uniquely powerful security model.  This
-model allows Zope developers to create components that work safely in
-an environment used by many different users, all with varying levels
-of security privledge.
-
-This section describes Zope's security model and how component
-developers can work with it and manipulate it to define security
-policies specific to their needs or the needs of their components.
-
-The majority of the content of this chapter will come from Chris'
-first cut at `Security documentation
-<http://www.zope.org/Members/mcdonc/PDG/6-1-Security.stx>`_
-
-1. Security architecture
-
-2. Using protected components
-
-3. Implementing Security in your Component
-
-4. Security Policies
-
-
-Debugging and Testing
-=====================
-
-Covers debugging Zope and unit testing.
-
-- pdb debugging
-
-- Control Panel debug view
-
-- -D z2.py switch
-
-- unit testing
-
-  - zope fixtures for unit testing

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/Products.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/Products.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/Products.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,1322 +0,0 @@
-#############
-Zope Products
-#############
-
-Introduction
-============
-
-Zope *products* extend Zope with new functionality.  Products most
-often provide new addable objects.  In this chapter, we are going to
-look at building products on the file system.  Filesystem products
-require more overhead to build, but offer more power and flexibility,
-and they can be developed with familiar tools such as text editors
-and version controlling systems.
-
-Soon we will make the examples referenced in this chapter available
-for download as an example product.  Until that time, you will see
-references to files in this chapter that are not available yet.  This
-will be made available soon.
-
-Development Process
-===================
-
-This chapter begins with a discussion of how you will develop
-products.  We'll focus on common engineering tasks that you'll
-encounter as you develop products.
-
-Consider Alternatives
----------------------
-
-Before you jump into the development of a product you should consider
-the alternatives.  Would your problem be better solved with External
-Methods, or Python Scripts? Products excel at extending Zope with new
-addable classes of objects.  If this does not figure centrally in
-your solution, you should look elsewhere.  Products, like External
-Methods allow you to write unrestricted Python code on the
-filesystem.
-
-Starting with Interfaces
-------------------------
-
-The first step in creating a product is to create one or more
-interfaces which describe the product.  See Chapter 2 for more
-information on interfaces and how to create them.
-
-Creating interfaces before you build an implementation is a good idea
-since it helps you see your design and assess how well it fulfills
-your requirements.
-
-Consider this interface for a multiple choice poll component (see
-`Poll.py <examples/Poll.py>`_)::
-
-  from zope.interface import Interface
-
-  class IPoll(Interface):
-      """A multiple choice poll"""
-
-      def castVote(index):
-          """Votes for a choice"""
-
-      def getTotalVotes():
-          """Returns total number of votes cast"""
-
-      def getVotesFor(index):
-          """Returns number of votes cast for a given response"""
-
-      def getResponses():
-          """Returns the sequence of responses"""
-
-      def getQuestion():
-          """Returns the question"""
-
-How you name your interfaces is entirely up to you.  Here we've
-decided to use prefix "I" in the name of the interface.
-
-Implementing Interfaces
------------------------
-
-After you have defined an interface for your product, the next step
-is to create a prototype in Python that implements your interface.
-
-Here is a prototype of a ``PollImplemtation`` class that implements the
-interface you just examined (see `PollImplementation.py
-<examples/PollImplementation.py>`_)::
-
-  from poll import Poll
-
-  class PollImplementation:
-      """A multiple choice poll, implements the Poll interface.
-
-      The poll has a question and a sequence of responses. Votes
-      are stored in a dictionary which maps response indexes to a
-      number of votes.
-      """
-
-      implements(IPoll)
-
-      def __init__(self, question, responses):
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-
-      def castVote(self, index):
-          """Votes for a choice"""
-          self._votes[index] = self._votes[index] + 1
-
-      def getTotalVotes(self):
-          """Returns total number of votes cast"""
-          total = 0
-          for v in self._votes.values():
-              total = total + v
-          return total
-
-      def getVotesFor(self, index):
-          """Returns number of votes cast for a given response"""
-          return self._votes[index]
-
-      def getResponses(self):
-          """Returns the sequence of responses"""
-          return tuple(self._responses)
-
-      def getQuestion(self):
-          """Returns the question"""
-          return self._question
-
-You can use this class interactively and test it.  Here's an example
-of interactive testing::
-
-  >>> from PollImplementation import PollImplementation
-  >>> p = PollImplementation("What's your favorite color?",
-  ...                        ["Red", "Green", "Blue", "I forget"])
-  >>> p.getQuestion()
-  "What's your favorite color?"
-  >>> p.getResponses()
-  ('Red', 'Green', 'Blue', 'I forget')
-  >>> p.getVotesFor(0)
-  0
-  >>> p.castVote(0)
-  >>> p.getVotesFor(0)
-  1
-  >>> p.castVote(2)
-  >>> p.getTotalVotes()
-  2
-  >>> p.castVote(4)
-  Traceback (innermost last):
-  File "<stdin>", line 1, in ?
-  File "PollImplementation.py", line 23, in castVote
-  self._votes[index] = self._votes[index] + 1
-  KeyError: 4
-
-Interactive testing is one of Python's great features.  It lets you
-experiment with your code in a simple but powerful way.
-
-At this point you can do a fair amount of work, testing and refining
-your interfaces and classes which implement them.  See Chapter 9 for
-more information on testing.
-
-So far you have learned how to create Python classes that are
-documented with interfaces, and verified with testing.  Next you'll
-examine the Zope product architecture.  Then you'll learn how to fit
-your well crafted Python classes into the product framework.
-
-Building Product Classes
-------------------------
-
-To turn a component into a product you must fulfill many contracts.
-For the most part these contracts are not yet defined in terms of
-interfaces.  Instead you must subclass from base classes that
-implement the contracts.  This makes building products confusing, and
-this is an area that we are actively working on improving.
-
-Base Classes
-------------
-
-Consider an example product class definition::
-
-  from Acquisition import Implicit
-  from Globals import Persistent
-  from AccessControl.Role import RoleManager
-  from OFS.SimpleItem import Item
-
-  class PollProduct(Implicit, Persistent, RoleManager, Item):
-      """
-      Poll product class
-      """
-      ...
-
-The order of the base classes depends on which classes you want to
-take precedence over others.  Most Zope classes do not define similar
-names, so you usually don't need to worry about what order these
-classes are used in your product.  Let's take a look at each of these
-base classes.
-
-
-Acquisition.Implicit
-~~~~~~~~~~~~~~~~~~~~
-
-This is the normal acquisition base class.  See the *API Reference*
-for the full details on this class.  Many Zope services such as
-object publishing and security use acquisition, so inheriting from
-this class is required for products.  Actually, you can choose to
-inherit from ``Acquisition.Explicit`` if you prefer, however, it will
-prevent folks from dynamically binding Python Scripts and DTML
-Methods to instances of your class.  In general you should subclass
-from ``Acquisition.Implicit`` unless you have a good reason not to.
-
-  XXX: is this true?  I thought that any ExtensionClass.Base can be
-  acquired.  The Implicit and Explicit just control how the class can
-  acquire, not how it *is* acquired.
-
-Globals.Persistent
-~~~~~~~~~~~~~~~~~~
-
-This base class makes instances of your product persistent.  For more
-information on persistence and this class see Chapter 4.
-
-In order to make your poll class persistent you'll need to make one
-change.  Since ``_votes`` is a dictionary this means that it's a
-mutable non-persistent sub-object.  You'll need to let the
-persistence machinery know when you change it::
-
-  def castVote(self, index):
-      """Votes for a choice"""
-      self._votes[index] = self._votes[index] + 1
-      self._p_changed = 1
-
-The last line of this method sets the ``_p_changed`` attribute to 1.
-This tells the persistence machinery that this object has changed and
-should be marked as ``dirty``, meaning that its new state should be
-written to the database at the conclusion of the current transaction.
-A more detailed explanation is given in the Persistence chapter of
-this guide.
-
-
-OFS.SimpleItem.Item
-~~~~~~~~~~~~~~~~~~~
-
-This base class provides your product with the basics needed to work
-with the Zope management interface.  By inheriting from ``Item`` your
-product class gains a whole host of features: the ability to be cut
-and pasted, capability with management views, WebDAV support, basic
-FTP support, undo support, ownership support, and traversal controls.
-It also gives you some standard methods for management views and
-error display including ``manage_main()``.  You also get the
-``getId()``, ``title_or_id()``, ``title_and_id()`` methods and the
-``this()`` DTML utility method.  Finally this class gives your
-product basic *dtml-tree* tag support.  ``Item`` is really an
-everything-but-the-kitchen-sink kind of base class.
-
-``Item`` requires that your class and instances have some management
-interface related attributes.
-
-- ``meta_type`` -- This attribute should be a short string which is
-  the name of your product class as it appears in the product add
-  list.  For example, the poll product class could have a
-  ``meta_type`` with value as ``Poll``.
-
-- ``id`` or ``__name__`` -- All ``Item`` instances must have an
-  ``id`` string attribute which uniquely identifies the instance
-  within it's container.  As an alternative you may use ``__name__``
-  instead of ``id``.
-
-- ``title`` -- All ``Item`` instances must have a ``title`` string
-  attribute.  A title may be an empty string if your instance does
-  not have a title.
-
-In order to make your poll class work correctly as an ``Item`` you'll
-need to make a few changes.  You must add a ``meta_type`` class
-attribute, and you may wish to add an ``id`` parameter to the
-constructor::
-
-  class PollProduct(..., Item):
-
-      meta_type = 'Poll'
-      ...
-
-      def __init__(self, id, question, responses):
-          self.id = id
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-
-
-Finally, you should probably place ``Item`` last in your list of base
-classes.  The reason for this is that ``Item`` provides defaults that
-other classes such as ``ObjectManager`` and ``PropertyManager``
-override.  By placing other base classes before ``Item`` you allow
-them to override methods in ``Item``.
-
-AccessControl.Role.RoleManager
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This class provides your product with the ability to have its
-security policies controlled through the web.  See Chapter 6 for more
-information on security policies and this class.
-
-OFS.ObjectManager
-~~~~~~~~~~~~~~~~~
-
-This base class gives your product the ability to contain other
-``Item`` instances.  In other words, it makes your product class like
-a Zope folder.  This base class is optional. See the *API Reference*
-for more details.  This base class gives you facilities for adding
-Zope objects, importing and exporting Zope objects, WebDAV, and FTP.
-It also gives you the ``objectIds``, ``objectValues``, and
-``objectItems`` methods.
-
-``ObjectManager`` makes few requirements on classes that subclass it.
-You can choose to override some of its methods but there is little
-that you must do.
-
-If you wish to control which types of objects can be contained by
-instances of your product you can set the ``meta_types`` class
-attribute.  This attribute should be a tuple of meta_types.  This
-keeps other types of objects from being created in or pasted into
-instances of your product.  The ``meta_types`` attribute is mostly
-useful when you are creating specialized container products.
-
-OFS.PropertyManager
-~~~~~~~~~~~~~~~~~~~
-
-This base class provides your product with the ability to have
-user-managed instance attributes.  See the *API Reference* for more
-details.  This base class is optional.
-
-Your class may specify that it has one or more predefined properties,
-by specifying a '_properties' class attribute.  For example::
-
-  _properties=({'id':'title', 'type': 'string', 'mode': 'w'},
-               {'id':'color', 'type': 'string', 'mode': 'w'},
-              )
-
-The ``_properties`` structure is a sequence of dictionaries, where
-each dictionary represents a predefined property.  Note that if a
-predefined property is defined in the ``_properties`` structure, you
-must provide an attribute with that name in your class or instance
-that contains the default value of the predefined property.
-
-Each entry in the ``_properties`` structure must have at least an
-``id`` and a ``type`` key.  The ``id`` key contains the name of the
-property, and the ``type`` key contains a string representing the
-object's type.  The ``type`` string must be one of the values:
-``float``, ``int``, ``long``, ``string``, ``lines``, ``text``,
-``date``, ``tokens``, ``selection``, or ``multiple section``.  For
-more information on Zope properties see the *Zope Book*.
-
-For ``selection`` and ``multiple selection`` properties, you must
-include an addition item in the property dictionary,
-``select_variable`` which provides the name of a property or method
-which returns a list of strings from which the selection(s) can be
-chosen.  For example::
-
-  _properties=({'id' : 'favorite_color',
-                'type' : 'selection',
-                'select_variable' : 'getColors'
-               },
-              )
-
-Each entry in the ``_properties`` structure may optionally provide a
-``mode`` key, which specifies the mutability of the property. The
-``mode`` string, if present, must be ``w``, ``d``, or ``wd``.
-
-A ``w`` present in the mode string indicates that the value of the
-property may be changed by the user.  A ``d`` indicates that the user
-can delete the property.  An empty mode string indicates that the
-property and its value may be shown in property listings, but that it
-is read-only and may not be deleted.
-
-Entries in the ``_properties`` structure which do not have a ``mode``
-item are assumed to have the mode ``wd`` (writable and deleteable).
-
-Security Declarations
----------------------
-
-In addition to inheriting from a number of standard base classes, you
-must declare security information in order to turn your component
-into a product.  See Chapter 6 for more information on security and
-instructions for declaring security on your components.
-
-Here's an example of how to declare security on the poll class::
-
-  from AccessControl import ClassSecurityInfo
-
-  class PollProduct(...):
-      ...
-
-      security = ClassSecurityInfo()
-
-      security.declareProtected('Use Poll', 'castVote')
-      def castVote(self, index):
-          ...
-
-      security.declareProtected('View Poll results', 'getTotalVotes')
-      def getTotalVotes(self):
-          ...
-
-      security.declareProtected('View Poll results', 'getVotesFor')
-      def getVotesFor(self, index):
-          ...
-
-      security.declarePublic('getResponses')
-      def getResponses(self):
-          ...
-
-      security.declarePublic('getQuestion')
-      def getQuestion(self):
-          ...
-
-For security declarations to be set up Zope requires that you
-initialize your product class.  Here's how to initialize your poll
-class::
-
-  from Globals import InitializeClass
-
-  class PollProduct(...):
-     ...
-
-  InitializeClass(PollProduct)
-
-Summary
--------
-
-Congratulations, you've created a product class.  Here it is in all
-its glory (see `examples/PollProduct.py <PollProduct.py>`_)::
-
-  from Poll import Poll
-  from AccessControl import ClassSecurityInfo
-  from Globals import InitializeClass
-  from Acquisition import Implicit
-  from Globals import Persistent
-  from AccessControl.Role import RoleManager
-  from OFS.SimpleItem import Item
-
-  class PollProduct(Implicit, Persistent, RoleManager, Item):
-      """Poll product class, implements Poll interface.
-
-      The poll has a question and a sequence of responses. Votes
-      are stored in a dictionary which maps response indexes to a
-      number of votes.
-      """
-
-      implements(IPoll)
-
-      meta_type = 'Poll'
-
-      security = ClassSecurityInfo()
-
-      def __init__(self, id, question, responses):
-          self.id = id
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-
-      security.declareProtected('Use Poll', 'castVote')
-      def castVote(self, index):
-          "Votes for a choice"
-          self._votes[index] = self._votes[index] + 1
-          self._p_changed = 1
-
-      security.declareProtected('View Poll results', 'getTotalVotes')
-      def getTotalVotes(self):
-          "Returns total number of votes cast"
-          total = 0
-          for v in self._votes.values():
-              total = total + v
-          return total
-
-      security.declareProtected('View Poll results', 'getVotesFor')
-      def getVotesFor(self, index):
-          "Returns number of votes cast for a given response"
-          return self._votes[index]
-
-      security.declarePublic('getResponses')
-      def getResponses(self):
-          "Returns the sequence of responses"
-          return tuple(self._responses)
-
-      security.declarePublic('getQuestion')
-      def getQuestion(self):
-          "Returns the question"
-          return self._question
-
-  InitializeClass(Poll)
-
-Now it's time to test your product class in Zope.  To do this you
-must register your product class with Zope.
-
-Registering Products
-====================
-
-Products are Python packages that live in 'lib/python/Products'.
-Products are loaded into Zope when Zope starts up.  This process is
-called *product initialization*.  During product initialization, each
-product is given a chance to register its capabilities with Zope.
-
-Product Initialization
-----------------------
-
-When Zope starts up it imports each product and calls the product's
-'initialize' function passing it a registrar object.  The
-'initialize' function uses the registrar to tell Zope about its
-capabilities.  Here is an example '__init__.py' file::
-
-  from PollProduct import PollProduct, addForm, addFunction
-
-  def initialize(registrar):
-      registrar.registerClass(
-          PollProduct,
-          constructors=(addForm, addFunction),
-          )
-
-This function makes one call to the *registrar* object which
-registers a class as an addable object.  The *registrar* figures out
-the name to put in the product add list by looking at the 'meta_type'
-of the class.  Zope also deduces a permission based on the class's
-meta-type, in this case *Add Polls* (Zope automatically pluralizes
-"Poll" by adding an "s").  The 'constructors' argument is a tuple of
-objects consisting of two functions: an add form which is called when
-a user selects the object from the product add list, and the add
-method which is the method called by the add form.  Note that these
-functions are protected by the constructor permission.
-
-Note that you cannot restrict which types of containers can contain
-instances of your classes.  In other words, when you register a
-class, it will appear in the product add list in folders if the user
-has the constructor permission.
-
-See the *API Reference* for more information on the
-``ProductRegistrar`` interface.
-
-Factories and Constructors
---------------------------
-
-Factories allow you to create Zope objects that can be added to
-folders and other object managers.  Factories are discussed in
-Chapter 12 of the *Zope Book*.  The basic work a factory does is to
-put a name into the product add list and associate a permission and
-an action with that name.  If you have the required permission then
-the name will appear in the product add list, and when you select the
-name from the product add list, the action method will be called.
-
-Products use Zope factory capabilities to allow instances of product
-classes to be created with the product add list.  In the above
-example of product initialization you saw how a factory is created by
-the product registrar.  Now let's see how to create the add form and
-the add list.
-
-The add form is a function that returns an HTML form that allows a
-users to create an instance of your product class.  Typically this
-form collects that id and title of the instance along with other
-relevant data.  Here's a very simple add form function for the poll
-class::
-
-  def addForm():
-      """Returns an HTML form."""
-      return """<html>
-      <head><title>Add Poll</title></head>
-      <body>
-      <form action="addFunction">
-      id <input type="type" name="id"><br>
-      question <input type="type" name="question"><br>
-      responses (one per line)
-      <textarea name="responses:lines"></textarea>
-      </form>
-      </body>
-      </html>"""
-
-Notice how the action of the form is ``addFunction``.  Also notice
-how the lines of the response are marshalled into a sequence.  See
-Chapter 2 for more information about argument marshalling and object
-publishing.
-
-It's also important to include a HTML ``head`` tag in the add form.
-This is necessary so that Zope can set the base URL to make sure that
-the relative link to the ``addFunction`` works correctly.
-
-The add function will be passed a ``FactoryDispatcher`` as its first
-argument which proxies the location (usually a Folder) where your
-product was added.  The add function may also be passed any form
-variables which are present in your add form according to normal
-object publishing rules.
-
-Here's an add function for your poll class::
-
-  def addFunction(dispatcher, id, question, responses):
-      """Create a new poll and add it to myself
-      """
-      p = PollProduct(id, question, responses)
-      dispatcher.Destination()._setObject(id, p)
-
-The dispatcher has three methods:
-
-- ``Destination`` -- The ``ObjectManager`` where your product was added.
-
-- ``DestinationURL`` -- The URL of the ``ObjectManager`` where your
-  product was added.
-
-- ``manage_main`` -- Redirects to a management view of the
-  ``ObjectManager`` where your product was added.
-
-Notice how it calls the ``_setObject()`` method of the destination
-``ObjectManager`` class to add the poll to the folder.  See the *API
-Reference* for more information on the ``ObjectManager`` interface.
-
-The add function should also check the validity of its input.  For
-example the add function should complain if the question or response
-arguments are not of the correct type.
-
-Finally you should recognize that the constructor functions are *not*
-methods on your product class.  In fact they are called before any
-instances of your product class are created.  The constructor
-functions are published on the web so they need to have doc strings,
-and are protected by a permission defined in during product
-initialization.
-
-Testing
--------
-
-Now you're ready to register your product with Zope.  You need to add
-the add form and add method to the poll module.  Then you should
-create a `Poll` directory in your `lib/python/Products` directory and
-add the `Poll.py`, `PollProduct.py`, and `__init__.py` files.  Then
-restart Zope.
-
-Now login to Zope as a manager and visit the web management
-interface.  You should see a 'Poll' product listed inside the
-*Products* folder in the *Control_Panel*.  If Zope had trouble
-initializing your product you will see a traceback here.  Fix your
-problems, if any and restart Zope.  If you are tired of all this
-restarting, take a look at the *Refresh* facility covered in Chapter
-7.
-
-Now go to the root folder.  Select *Poll* from the product add list.
-Notice how you are taken to the add form.  Provide an id, a question,
-and a list of responses and click *Add*.  Notice how you get a black
-screen.  This is because your add method does not return anything.
-Notice also that your poll has a broken icon, and only has the
-management views.  Don't worry about these problems now, you'll find
-out how to fix these problems in the next section.
-
-Now you should build some DTML Methods and Python Scripts to test
-your poll instance.  Here's a Python Script to figure out voting
-percentages::
-
-  ## Script (Python) "getPercentFor"
-  ##parameters=index
-  ##
-  """Returns the percentage of the vote given a response index. Note,
-  this script should be bound a poll by acquisition context."""
-  poll = context
-  return float(poll.getVotesFor(index)) / poll.getTotalVotes()
-
-
-Here's a DTML Method that displays poll results and allows you to
-vote::
-
-  <dtml-var standard_html_header>
-
-  <h2>
-    <dtml-var getQuestion>
-  </h2>
-
-  <form> <!-- calls this dtml method -->
-
-  <dtml-in getResponses>
-    <p>
-      <input type="radio" name="index" value="&dtml-sequence-index;">
-      <dtml-var sequence-item>
-    </p>
-  </dtml-in>
-
-  <input type="submit" value=" Vote ">
-
-  </form>
-
-  <!-- process form -->
-
-  <dtml-if index>
-    <dtml-call expr="castVote(index)">
-  </dtml-if>
-
-  <!-- display results -->
-
-  <h2>Results</h2>
-
-  <p><dtml-var getTotalVotes> votes cast</p>
-
-  <dtml-in getResponses>
-    <p>
-      <dtml-var sequence-item> -
-      <dtml-var expr="getPercentFor(_.get('sequence-index'))">%
-    </p>
-  </dtml-in>
-
-  <dtml-var standard_html_footer>
-
-To use this DTML Method, call it on your poll instance.  Notice how
-this DTML makes calls to both your poll instance and the
-``getPercentFor`` Python script.
-
-At this point there's quite a bit of testing and refinement that you
-can do.  Your main annoyance will be having to restart Zope each time
-you make a change to your product class (but see Chapter 9 for
-information on how to avoid all this restarting).  If you vastly
-change your class you may break existing poll instances, and will
-need to delete them and create new ones.  See Chapter 9 for more
-information on debugging techniques which will come in handy.
-
-Building Management Interfaces
-------------------------------
-
-Now that you have a working product let's see how to beef up its user
-interface and create online management facilities.
-
-Defining Management Views
--------------------------
-
-All Zope products can be managed through the web.  Products have a
-collection of management tabs or *views* which allow managers to
-control different aspects of the product.
-
-A product's management views are defined in the ``manage_options``
-class attribute.  Here's an example::
-
-        manage_options=(
-            {'label' : 'Edit', 'action' : 'editMethod'},
-            {'label' : 'View', 'action' : 'viewMethod'},
-            )
-
-The ``manage_options`` structure is a tuple that contains
-dictionaries.  Each dictionary defines a management view.  The view
-dictionary can have a number of items.
-
-- 'label' -- This is the name of the management view
-
-- 'action' -- This is the URL that is called when the view is
-  chosen. Normally this is the name of a method that displays a
-  management view.
-
-- 'target' -- An optional target frame to display the action. This
-  item is rarely needed.
-
-- 'help' -- Optional help information associated with the
-  view. You'll find out more about this option later.
-
-Management views are displayed in the order they are defined.
-However, only those management views for which the current user has
-permissions are displayed.  This means that different users may see
-different management views when managing your product.
-
-Normally you will define a couple custom views and reusing some
-existing views that are defined in your base classes.  Here's an
-example::
-
-  class PollProduct(..., Item):
-      ...
-
-      manage_options=(
-          {'label' : 'Edit', 'action' : 'editMethod'},
-          {'label' : 'Options', 'action' : 'optionsMethod'},
-          ) + RoleManager.manage_options + Item.manage_options
-
-This example would include the standard management view defined by
-``RoleManager`` which is *Security* and those defined by ``Item``
-which are *Undo* and *Ownership*.  You should include these standard
-management views unless you have good reason not to. If your class
-has a default view method (``index_html``) you should also include a
-*View* view whose action is an empty string.  See Chapter 2 for more
-information on ``index_html``.
-
-Note: you should not make the *View* view the first view on your
-class.  The reason is that the first management view is displayed
-when you click on an object in the Zope management interface.  If the
-*View* view is displayed first, users will be unable to navigate to
-the other management views since the view tabs will not be visible.
-
-Creating Management Views
--------------------------
-
-The normal way to create management view methods is to use DTML.  You
-can use the ``DTMLFile`` class to create a DTML Method from a file.
-For example::
-
-  from Globals import DTMLFile
-
-  class PollProduct(...):
-    ...
-
-    editForm = DTMLFile('dtml/edit', globals())
-    ...
-
-This creates a DTML Method on your class which is defined in the
-`dtml/edit.dtml` file.  Notice that you do not have to include the
-``.dtml`` file extension.  Also, don't worry about the forward slash
-as a path separator; this convention will work fine on Windows. By
-convention DTML files are placed in a ``dtml`` subdirectory of your
-product.  The ``globals()`` argument to the ``DTMLFile`` constructor
-allows it to locate your product directory.  If you are running Zope
-in debug mode then changes to DTML files are reflected right away. In
-other words you can change the DTML of your product's views without
-restarting Zope to see the changes.
-
-DTML class methods are callable directly from the web, just like
-other methods.  So now users can see your edit form by calling the
-``editForm`` method on instances of your poll class.  Typically DTML
-methods will make calls back to your instance to gather information
-to display.  Alternatively you may decide to wrap your DTML methods
-with normal methods.  This allows you to calculate information needed
-by your DTML before you call it.  This arrangement also ensures that
-users always access your DTML through your wrapper.  Here's an
-example::
-
-  from Globals import DTMLFile
-
-  class PollProduct(...):
-    ...
-
-    _editForm = DTMLFile('dtml/edit', globals())
-
-    def editForm(self, ...):
-        ...
-
-        return self._editForm(REQUEST, ...)
-
-
-When creating management views you should include the DTML variables
-``manage_page_header`` and ``manage_tabs`` at the top, and
-``manage_page_footer`` at the bottom.  These variables are acquired
-by your product and draw a standard management view header, tabs
-widgets, and footer.  The management header also includes CSS
-information which you can take advantage of if you wish to add CSS
-style information to your management views.  The management CSS
-information is defined in the
-`lib/python/App/dtml/manage_page_style.css.dtml`` file.  Here are the
-CSS classes defined in this file and conventions for their use.
-
-- 'form-help' -- Explanatory text related to forms.  In the future,
-  users may have the option to hide this text.
-
-- 'std-text' -- Declarative text unrelated to forms.  You should
-  rarely use this class.
-
-- 'form-title' -- Form titles.
-
-- 'form-label' -- Form labels for required form elements.
-
-- 'form-optional' -- Form labels for optional form elements.
-
-- 'form-element' -- Form elements.  Note, because of a Netscape bug,
-  you should not use this class on 'textarea' elements.
-
-- 'form-text' -- Declarative text in forms.
-
-- 'form-mono' -- Fixed width text in forms.  You should rarely use
-  this class.
-
-Here's an example management view for your poll class.  It allows you
-to edit the poll question and responses (see ``editPollForm.dtml``)::
-
-  <dtml-var manage_page_header>
-  <dtml-var manage_tabs>
-
-  <p class="form-help">
-  This form allows you to change the poll's question and
-  responses. <b>Changing a poll's question and responses
-  will reset the poll's vote tally.</b>.
-  </p>
-
-  <form action="editPoll">
-  <table>
-
-    <tr valign="top">
-      <th class="form-label">Question</th>
-      <td><input type="text" name="question" class="form-element"
-      value="&dtml-getQuestion;"></td>
-    </tr>
-
-    <tr valign="top">
-      <th class="form-label">Responses</th>
-      <td><textarea name="responses:lines" cols="50" rows="10">
-      <dtml-in getResponses>
-      <dtml-var sequence-item html_quote>
-      </dtml-in>
-      </textarea>
-      </td>
-    </tr>
-
-    <tr>
-      <td></td>
-      <td><input type="submit" value="Change" class="form-element"></td>
-    </tr>
-
-  </table>
-  </form>
-
-  <dtml-var manage_page_header>
-
-This DTML method displays an edit form that allows you to change the
-questions and responses of your poll.  Notice how poll properties are
-HTML quoted either by using ``html_quote`` in the ``dtml-var`` tag,
-or by using the ``dtml-var`` entity syntax.
-
-Assuming this DTML is stored in a file ``editPollForm.dtml`` in your
-product's ``dtml`` directory, here's how to define this method on
-your class::
-
-  class PollProduct(...):
-      ...
-
-      security.declareProtected('View management screens', 'editPollForm')
-      editPollForm = DTML('dtml/editPollForm', globals())
-
-Notice how the edit form is protected by the `View management
-screens` permission.  This ensures that only managers will be able to
-call this method.
-
-Notice also that the action of this form is ``editPoll``.  Since the
-poll as it stands doesn't include any edit methods you must define
-one to accept the changes.  Here's an ``editPoll`` method::
-
-  class PollProduct(...):
-      ...
-
-      def __init__(self, id, question, responses):
-          self.id = id
-          self.editPoll(question, response)
-
-      ...
-
-      security.declareProtected('Change Poll', 'editPoll')
-      def editPoll(self, question, responses):
-          """
-          Changes the question and responses.
-          """
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-
-Notice how the ``__init__`` method has been refactored to use the new
-``editPoll`` method.  Also notice how the ``editPoll`` method is
-protected by a new permissions, ``Change Poll``.
-
-There still is a problem with the ``editPoll`` method.  When you call
-it from the ``editPollForm`` through the web nothing is returned.
-This is a bad management interface.  You want this method to return
-an HTML response when called from the web, but you do not want it to
-do this when it is called from ``__init__``.  Here's the solution::
-
-  class Poll(...):
-      ...
-
-      def editPoll(self, question, responses, REQUEST=None):
-          """Changes the question and responses."""
-          self._question = question
-          self._responses = responses
-          self._votes = {}
-          for i in range(len(responses)):
-              self._votes[i] = 0
-          if REQUEST is not None:
-              return self.editPollForm(REQUEST,
-                  manage_tabs_message='Poll question and responses changed.')
-
-If this method is called from the web, then Zope will automatically
-supply the ``REQUEST`` parameter.  (See chapter 4 for more
-information on object publishing).  By testing the ``REQUEST`` you
-can find out if your method was called from the web or not.  If you
-were called from the web you return the edit form again.
-
-A management interface convention that you should use is the
-``manage_tab_message`` DTML variable.  If you set this variable when
-calling a management view, it displays a status message at the top of
-the page.  You should use this to provide feedback to users
-indicating that their actions have been taken when it is not obvious.
-For example, if you don't return a status message from your
-``editPoll`` method, users may be confused and may not realize that
-their changes have been made.
-
-Sometimes when displaying management views, the wrong tab will be
-highlighted.  This is because 'manage_tabs' can't figure out from the
-URL which view should be highlighted.  The solution is to set the
-'management_view' variable to the label of the view that should be
-highlighted.  Here's an example, using the 'editPoll' method::
-
-  def editPoll(self, question, responses, REQUEST=None):
-      """
-      Changes the question and responses.
-      """
-      self._question = question
-      self._responses = responses
-      self._votes = {}
-      for i in range(len(responses)):
-          self._votes[i] = 0
-      if REQUEST is not None:
-          return self.editPollForm(REQUEST,
-              management_view='Edit',
-              manage_tabs_message='Poll question and responses changed.')
-
-Now let's take a look a how to define an icon for your product.
-
-Icons
------
-
-Zope products are identified in the management interface with icons.
-An icon should be a 16 by 16 pixel GIF image with a transparent
-background.  Normally icons files are located in a ``www``
-subdirectory of your product package.  To associate an icon with a
-product class, use the ``icon`` parameter to the ``registerClass``
-method in your product's constructor.  For example::
-
-  def initialize(registrar):
-      registrar.registerClass(
-          PollProduct,
-          constructors=(addForm, addFunction),
-          icon='www/poll.gif'
-          )
-
-Notice how in this example, the icon is identified as being within
-the product's ``www`` subdirectory.
-
-See the *API Reference* for more information on the ``registerClass``
-method of the ``ProductRegistrar`` interface.
-
-Online Help
------------
-
-Zope has an online help system that you can use to provide help for
-your products.  Its main features are context-sensitive help and API
-help.  You should provide both for your product.
-
-
-Context Sensitive Help
-----------------------
-
-To create context sensitive help, create one help file per management
-view in your product's ``help`` directory.  You have a choice of
-formats including: HTML, DTML, structured text, GIF, JPG, and PNG.
-
-Register your help files at product initialization with the
-``registerHelp()`` method on the registrar object::
-
-  def initialize(registrar):
-      ...
-      registrar.registerHelp()
-
-This method will take care of locating your help files and creating
-help topics for each help file.  It can recognize these file
-extensions: ``.html``, ``.htm``, ``.dtml``, ``.txt``, ``.stx``,
-``.gif``, ``.jpg``, ``.png``.
-
-If you want more control over how your help topics are created you
-can use the ``registerHelpTopic()`` method which takes an id and a
-help topic object as arguments.  For example::
-
-  from mySpecialHelpTopics import MyTopic
-
-  def initialize(context):
-      ...
-      context.registerHelpTopic('myTopic', MyTopic())
-
-Your help topic should adhere to the 'HelpTopic' interface. See the
-*API Reference* for more details.
-
-The chief way to bind a help topic to a management screen is to
-include information about the help topic in the class's
-manage_options structure. For example::
-
-  manage_options = (
-      {'label': 'Edit',
-       'action': 'editMethod',
-       'help': ('productId','topicId')},
-      )
-
-The `help` value should be a tuple with the name of your product's
-Python package, and the file name (or other id) of your help topic.
-Given this information, Zope will automatically draw a *Help* button
-on your management screen and link it to your help topic.
-
-To draw a help button on a management screen that is not a view (such
-as an add form), use the 'HelpButton' method of the 'HelpSys' object
-like so::
-
-  <dtml-var "HelpSys.HelpButton('productId', 'topicId')">
-
-This will draw a help button linked to the specified help topic.  If
-you prefer to draw your own help button you can use the helpURL
-method instead like so::
-
-  <dtml-var "HelpSys.helpURL(
-    topic='productId',
-    product='topicId')">
-
-This will give you a URL to the help topic.  You can choose to draw
-whatever sort of button or link you wish.
-
-Other User Interfaces
----------------------
-
-In addition to providing a through the web management interface your
-products may also support many other user interfaces.  You product
-might have no web management interfaces, and might be controlled
-completely through some other network protocol.  Zope provides
-interfaces and support for FTP, WebDAV and XML-RPC.  If this isn't
-enough you can add other protocols.
-
-FTP and WebDAV Interfaces
--------------------------
-
-Both FTP and WebDAV treat Zope objects like files and
-directories.  See Chapter 3 for more information on FTP and WebDAV.
-
-By simply sub-classing from 'SimpleItem.Item' and 'ObjectManager' if
-necessary, you gain basic FTP and WebDAV support.  Without any work
-your objects will appear in FTP directory listings and if your class
-is an 'ObjectManager' its contents will be accessible via FTP and
-WebDAV.  See Chapter 2 for more information on implementing FTP and
-WebDAV support.
-
-XML-RPC and Network Services
-----------------------------
-
-XML-RPC is covered in Chapter 2.  All your product's methods can be
-accessible via XML-RPC.  However, if your are implementing network
-services, you should explicitly plan one or more methods for use with
-XML-RPC.
-
-Since XML-RPC allows marshalling of simple strings, lists, and
-dictionaries, your XML-RPC methods should only accept and return
-these types.  These methods should never accept or return Zope
-objects.  XML-RPC also does not support 'None' so you should use zero
-or something else in place of 'None'.
-
-Another issue to consider when using XML-RPC is security.  Many
-XML-RPC clients still don't support HTTP basic authorization.
-Depending on which XML-RPC clients you anticipate, you may wish to
-make your XML-RPC methods public and accept authentication
-credentials as arguments to your methods.
-
-Content Management Framework Interface
---------------------------------------
-
-The `Content Management Framework <http://cmf.zope.org>`_ is an
-evolving content management extension for Zope.  It provides a number
-of interfaces and conventions for content objects.  If you wish to
-support the CMF you should consult the CMF user interface guidelines
-and interface documentation.
-
-Supporting the CMF interfaces is not a large burden if you already
-support the Zope management interface.  You should consider
-supporting the CMF if your product class handles user manageable
-content such as documents, images, business forms, etc.
-
-Packaging Products
-------------------
-
-Zope products are normally packaged as tarballs.  You should create
-your product tarball in such a way as to allow it to be unpacked in
-the Products directory.  For example, `cd` to the Products directory
-and then issue a `tar` comand like so::
-
-  $ tar zcvf MyProduct-1.0.1.tgz MyProduct
-
-This will create a gzipped tar archive containing your product.  You
-should include your product name and version number in file name of
-the archive.
-
-See the `Poll-1.0.tgz <examples/Poll-1.0.tgz>`_ file for an example
-of a fully packaged Python product.
-
-
-Product Information Files
--------------------------
-
-Along with your Python and ZPT files you should include some
-information about your product in its root directory.
-
-- `README.txt` -- Provides basic information about your product.
-   Zope will parse this file as StructuredText and make it available
-   on the *README* view of your product in the control panel.
-
-- `VERSION.txt` -- Contains the name and version of your product on a
-  single line. For example, 'Multiple Choice Poll 1.1.0'.  Zope will
-  display this information as the 'version' property of your product
-  in the control panel.
-
-- `LICENSE.txt` -- Contains your product license, or a link to it.
-
-You may also wish to provide additional information.  Here are some
-suggested optional files to include with your product.
-
-- `INSTALL.txt` -- Provides special instructions for installing the
-  product and components on which it depends.  This file is only
-  optional if your product does not require more than an ungzip/untar
-  into a Zope installation to work.
-
-- `TODO.txt` -- This file should make clear where this product
-  release needs work, and what the product author intends to do about
-  it.
-
-- `CHANGES.txt` and `HISTORY.txt` -- 'CHANGES.txt' should enumerate
-  changes made in particular product versions from the last release
-  of the product. Optionally, a 'HISTORY.txt' file can be used for
-  older changes, while 'CHANGES.txt' lists only recent changes.
-
-- `DEPENDENCIES.txt` -- Lists dependencies including required os
-  platform, required Python version, required Zope version, required
-  Python packages, and required Zope products.
-
-Product Directory Layout
-------------------------
-
-By convention your product will contain a number of sub-directories.
-Some of these directories have already been discussed in this
-chapter. Here is a summary of them.
-
-- `www` -- Contains your icon & ZPT files.
-
-- `help` -- Contains your help files.
-
-- `tests` -- Contains your unit tests.
-
-It is not necessary to include these directories if your don't have
-anything to go in them.
-
-Evolving Products
-=================
-
-As you develop your product classes you will generally make a series
-of product releases.  While you don't know in advance how your
-product will change, when it does change there are measures that you
-can take to minimize problems.
-
-Evolving Classes
-----------------
-
-Issues can occur when you change your product class because instances
-of these classes are generally persistent.  This means that instances
-created with an old class will start using a new class.  If your
-class changes drastically this can break existing instances.
-
-The simplest way to handle this situation is to provide class
-attributes as defaults for newly added attributes.  For example if
-the latest version of your class expects an 'improved_spam' instance
-attribute while earlier versions only sported 'spam' attributes, you
-may wish to define an 'improved_spam' class attribute in your new
-class so your old objects won't break when they run with your new
-class.  You might set 'improved_spam' to None in your class, and in
-methods where you use this attribute you may have to take into
-account that it may be None.  For example::
-
-  class Sandwich(...):
-
-      improved_spam = None
-      ...
-
-      def assembleSandwichMeats(self):
-          ...
-          # test for old sandwich instances
-          if self.improved_spam is None:
-              self.updateToNewSpam()
-          ...
-
-Another solution is to use the standard Python pickling hook
-'__setstate__', however, this is in general more error prone and
-complex.
-
-A third option is to create a method to update old instances.  Then
-you can manually call this method on instances to update to them.
-Note, this won't work unless the instances function well enough to be
-accessible via the Zope management screens.
-
-While you are developing a product you won't have to worry too much
-about these details, since you can always delete old instances that
-break with new class definitions.  However, once you release your
-product and other people start using it, then you need to start
-planning for the eventuality of upgrading.
-
-Another nasty problem that can occur is breakage caused by renaming
-your product classes.  You should avoid this since it breaks all
-existing instances.  If you really must change your class name,
-provide aliases to it using the old name.  You may however, change
-your class's base classes without causing these kinds of problems.
-
-Evolving Interfaces
--------------------
-
-The basic rule of evolving interfaces is *don't do it*.  While you
-are working privately you can change your interfaces all you wish.
-But as soon as you make your interfaces public you should freeze
-them.  The reason is that it is not fair to users of your interfaces
-to changes them after the fact.  An interface is contract.  It
-specifies how to use a component and it specifies how to implement
-types of components.  Both users and developers will have problems if
-your change the interfaces they are using or implementing.
-
-The general solution is to create simple interfaces in the first
-place, and create new ones when you need to change an existing
-interface.  If your new interfaces are compatible with your existing
-interfaces you can indicate this by making your new interfaces extend
-your old ones.  If your new interface replaces an old one but does
-not extend it you should give it a new name such as,
-``WidgetWithBellsOn``.  Your components should continue to support
-the old interface in addition to the new one for a few releases.
-
-Conclusion
-==========
-
-Migrating your components into fully fledged Zope products is a
-process with a number of steps.  There are many details to keep track
-of.  However, if you follow the recipe laid out in this chapter you
-should have no problems.
-
-Zope products are a powerful framework for building web applications.
-By creating products you can take advantage of Zope's features
-including security, scalability, through the web management, and
-collaboration.

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/Security.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/Security.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/Security.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,1300 +0,0 @@
-########
-Security
-########
-
-Introduction
-============
-
-A typical web application needs to be securely managed.  Different
-types of users need different kinds of access to the components that
-make up an application. To this end, Zope includes a comprehensive
-set of security features.  This chapter's goal is to shed light on
-Zope security in the context of Zope Product development.  For a more
-fundamental overview of Zope security, you may wish to refer to the
-*Zope Book*, Chapter 6, Users and Security.  Before diving into this
-chapter, you should have a basic understanding of how to build Zope
-Products as well as an understanding of how the Zope object publisher
-works. These topics are covered in Chapter 2 and Chapter 3,
-respectively.
-
-
-Security Architecture
-=====================
-
-The Zope security architecture is built around a *security policy*,
-which you can think of as the "access control philosophy" of
-Zope. This policy arbitrates the decisions Zope makes about whether
-to allow or deny access to any particular object defined within the
-system.
-
-How The Security Policy Relates to Zope's Publishing Machinery
---------------------------------------------------------------
-
-When access to Zope is performed via HTTP, WebDAV, or FTP, Zope's
-publishing machinery consults the security policy in order to
-determine whether to allow or deny access to a visitor for a
-particular object.  For example, when a user visits the root
-'index_html' object of your site via HTTP, the security policy is
-consulted by 'ZPublisher' to determine whether the user has
-permission to view the 'index_html' object itself.  For more
-information on this topic, see Chapter 3, "Object Publishing".
-
-The Zope security policy is consulted when an object is accessed the
-publishing machinery, for example when a web request is submitted.
-
-
-How The Security Policy Relates to Restricted Code
---------------------------------------------------
-
-*Restricted code* is generally any sort of logic that may be edited
-remotely (through the Web, FTP, via WebDAV or by other means). DTML
-Methods, SQLMethods, Python Scripts and Perl Scripts are examples of
-restricted code.
-
-When restricted code runs, any access to objects integrated with Zope
-security is arbitrated by the security policy. For example if you
-write a bit of restricted code with a line that attempts to
-manipulate an object you don't have sufficient permission to use, the
-security policy will deny you access to the object.  This generally
-is accomplished by raising an 'Unauthorized' exception, which is a
-Python string exception caught by a User Folder which signifies that
-Zope should attempt to get user credentials before obeying the
-request.  The particular code used to attempt to obtain the
-credentials is determined by the User Folder "closest" (folder-wise)
-to the object being accessed.
-
-The Zope security policy is consulted when an object is accessed by
-restricted code.
-
-'Unauthorized' Exceptions and Through-The-Web Code
---------------------------------------------------
-
-The security policy infrastructure will raise an 'Unauthorized'
-exception automatically when access to an object is denied.  When an
-'Unauthorized' exception is raised within Zope, it is handled in a
-sane way by Zope, generally by having the User Folder prompt the user
-for login information.  Using this functionality, it's possible to
-protect Zope objects through access control, only prompting the user
-for authentication when it is necessary to perform an action which
-requires privilege.
-
-An example of this behavior can be witnessed within the Zope
-Management interface itself.  The management interface prompts you to
-log in when visiting, for example, the '/manage' method of any Zope
-object.  This is due to the fact that an anonymous user does not
-generally possess the proper credentials to use the management
-interface.  If you're using Zope in the default configuration with
-the default User Folder, it prompts you to provide login information
-via an HTTP basic authentication dialog.
-
-How The Security Policy Relates To Unrestricted Code
-----------------------------------------------------
-
-There are also types of *unrestricted code* in Zope, where the logic
-is not constrained by the security policy. Examples of unrestricted
-code are the methods of Python classes that implement the objects in
-Python file-based add-on components.  Another example of unrestricted
-code can be found in External Method objects, which are defined in
-files on the filesystem.  These sorts of code are allowed to run
-"unrestricted" because access to the file system is required to
-define such logic.  Zope assumes that code defined on the filesystem
-is "trusted", while code defined "through the web" is not.  All
-filesystem-based code in Zope is unrestricted code.
-
-We'll see later that while the security policy does not constrain
-what your unrestricted code does, it can and should be used to
-control the ability to *call* your unrestricted code from within a
-restricted-code environment.
-
-The Zope security policy is *not* consulted when unrestricted code is
-run.
-
-Details Of The Default Zope Security Policy
--------------------------------------------
-
-In short, the default Zope security policy ensures the following:
-
-- access to an object which does not have any associated security
-  information is always denied.
-
-- if an object is associated with a permission, access is granted or
-  denied based on the user's roles.  If a user has a role which has
-  been granted the permission in question, access is granted.  If the
-  user does not possess a role that has been granted the permission
-  in question, access is denied.
-
-- if the object has a security assertion declaring it *public* , then
-  access will be granted.
-
-- if the object has a security assertion declaring it *private*, then
-  access will be denied.
-
-- accesses to objects that have names beginning with the underscore
-  character '_' are always denied.
-
-As we delve further into Zope security within this chapter, we'll see
-exactly what it means to associate security information with an
-object.
-
-
-Overview Of Using Zope Security Within Your Product
----------------------------------------------------
-
-Of course, now that we know what the Zope security policy is, we need
-to know how our Product can make use of it.  Zope developers leverage
-the Zope security policy primarily by making security declarations
-related to methods and objects within their Products.  Using security
-assertions, developers may deny or allow all types of access to a
-particular object or method unilaterally, or they may protect access
-to Zope objects more granularly by using permissions to grant or deny
-access based on the roles of the requesting user to the same objects
-or methods.
-
-
-For a more fundamental overview of Zope users, roles, and
-permissions, see the section titled "Authorization and Managing
-Security" in the Security Chapter of the *Zope Book*.
-
-Security Declarations In Zope Products
---------------------------------------
-
-Zope security declarations allow developers to make security
-assertions about a Product-defined object and its methods.
-Security declarations come in three basic forms.  These are:
-
-- public -- allow anybody to access the protected object
-  or method
-
-- private -- deny anyone access to the protected object or
-  method
-
-- protected -- protect access to the object or method via a
-  permission
-
-We'll see how to actually "spell" these security assertions a
-little later in this chapter.  In the meantime, just know that
-security declarations are fundamental to Zope Product security,
-and they can be used to protect access to an object by
-associating it with a permission.  We will refer to security
-declarations as "declarations" and "assertions" interchangeably
-within this chapter.
-
-
-Permissions In Zope Products
-============================
-
-A permission is the smallest unit of access to an object in Zope,
-roughly equivalent to the atomic permissions on files seen in Windows
-NT or UNIX: R (Read), W(Write), X(Execute), etc. However, unlike
-these types of mnemonic permissions shared by all sorts of different
-file types in an operating system product, in Zope, a permission
-usually describes a fine-grained logical operation which takes place
-upon an object, such as "View Management Screens" or "Add
-Properties".
-
-Zope administrators associate these permissions with *roles*, which
-they grant to Zope users.  Thus, declaring a protection assertion on
-a method of "View management screens" ensures that only users who
-possess roles which have been granted the "View management screens"
-permission are able to perform the action that the method defines.
-
-It is important to note that Zope's security architecture dictates
-that roles and users remain the domain of administrators, while
-permissions remain the domain of developers.  Developers of Products
-should not attempt to define roles or users, although they may (and
-usually must) define permissions.  Most importantly, a Zope
-administrator who makes use of your product should have the "last
-word" as regards which roles are granted which permissions, allowing
-her to protect her site in a manner that fits her business goals.
-
-Permission names are strings, and these strings are currently
-arbitrary.  There is no permission hierarchy, or list of "approved
-permissions".  Developers are encouraged to reuse Zope core
-permissions (e.g. "View", "Access contents information") when
-appropriate, or they may create their own as the need arises.  It is
-generally wise to reuse existing Zope permission names unless you
-specifically need to define your own.  For a list of existing Zope
-core permissions, see Appendix A, "Zope Core Permissions".
-
-Permissions are often tied to method declarations in Zope.  Any
-number of method declarations may share the same permission.  It's
-useful to declare the same permission on a set of methods which can
-logically be grouped together.  For example, two methods which return
-management forms for the object can be provided with the same
-permission, "View management screens".  Likewise, two entirely
-different objects can share a permission name to denote that the
-operation that's being protected is fundamentally similar.  For
-instance, most Product-defined objects reuse the Zope "View"
-permission, because most Zope objects need to be viewed in a web
-browser.  If you create an addable Zope class named 'MyObject', it
-doesn't make much sense to create a permission "View MyObject",
-because the generic "View" permission may be reused for this action.
-
-There is an exception to the "developers should not try to define
-roles" rule inasmuch as Zope allows developers to assign "default
-roles" to a permission.  This is primarily for the convenience of the
-Zope administrator, as default roles for a permission cause the Zope
-security machinery to provide a permission to a role *by default*
-when instances of a Product class are encountered during security
-operations.  For example, if your Product defines a permission "Add
-Poll Objects", this permission may be associated with a set of
-default roles, perhaps "Manager".  Default roles in Products should
-not be used against roles other than "Manager", "Anonymous", "Owner",
-and "Authenticated" (the four default Zope roles), as other roles are
-not guaranteed to exist in every Zope installation.
-
-Using security assertions in Zope is roughly analogous to assigning
-permission bit settings and ownership information to files in a UNIX
-or Windows filesystem.  Protecting objects via permissions allows
-developers and administrators to secure Zope objects independently of
-statements made in application code.
-
-Implementing Security In Python Products
-========================================
-
-Security Assertions
--------------------
-
-You may make several kinds of security assertions at the Python
-level.  You do this to declare accessibility of methods and
-subobjects of your classes. Three of the most common assertions that
-you'll want to make on your objects are:
-
-- this object is **public** (always accessible)
-
-- this object is **private** (not accessible by restricted code or by
-  URL traversal)
-
-- this object is **protected** by a specific permission
-
-There are a few other kinds of security assertions that are 
-much less frequently used but may be needed in some cases:
-
-- asserting that access to subobjects that do not have explicit
-  security information should be allowed rather than denied.
-
-- asserting what sort of protection should be used when determining
-  access to an *object itself* rather than a particular method of the
-  object
-
-It is important to understand that security assertions made in your
-Product code *do not* limit the ability of the code that the
-assertion protects.  Assertions only protect *access to this code*.
-The code which constitutes the body of a protected, private, or
-public method of a class defined in a Zope disk-based Product runs
-completely unrestricted, and is not subject to security constraints
-of any kind within Zope.  An exception to this rule occurs when
-disk-based-Product code calls a "through the web" method such as a
-Python Script or a DTML Method.  In this case, the security
-constraints imposed by these objects respective to the current
-request are obeyed.
-
-When Should I Use Security Assertions?
---------------------------------------
-
-If you are building an object that will be used from DTML or other
-restricted code, or that will be accessible directly through the web
-(or other remote protocols such as FTP or WebDAV) then you need to
-define security information for your object.
-
-Making Security Assertions
---------------------------
-
-As a Python developer, you make security assertions in your Python
-classes using 'SecurityInfo' objects. A 'SecurityInfo' object
-provides the interface for making security assertions about an object
-in Zope.
-
-The convention of placing security declarations inside Python code
-may at first seem a little strange if you're used to "plain old
-Python" which has no notion at all of security declarations.  But
-because Zope provides the ability to make these security assertions
-at such a low level, the feature is ubiquitous throughout Zope,
-making it easy to make these declarations once in your code, usable
-site-wide without much effort.
-
-Class Security Assertions
-=========================
-
-The most common kind of 'SecurityInfo' you will use as a component
-developer is the 'ClassSecurityInfo' object.  You use
-'ClassSecurityInfo' objects to make security assertions about methods
-on your classes.
-
-Classes that need security assertions are any classes that define
-methods that can be called "through the web".  This means any methods
-that can be called directly with URL traversal, from DTML Methods, or
-from Python-based Script objects.
-
-Declaring Class Security
-------------------------
-
-When writing the classes in your product, you create a
-'ClassSecurityInfo' instance *within each class that needs to play
-with the security model*. You then use the 'ClassSecurityInfo' object
-to make assertions about your class, its subobjects and its methods.
-
-The 'ClassSecurityInfo' class is defined in the 'AccessControl'
-package of the Zope framework. To declare class security information
-create a 'ClassSecurityInfo' class attribute named 'security'.  The
-name 'security' is used for consistency and for the benefit of new
-component authors, who often learn from looking at other people's
-code. You do not have to use the name 'security' for the security
-infrastructure to recognize your assertion information, but it is
-recommended as a convention.  For example::
-
-  from AccessControl import ClassSecurityInfo
-
-  class Mailbox(ObjectManager):
-    """A mailbox object that contains mail message objects."""
-
-    # Create a SecurityInfo for this class. We will use this 
-    # in the rest of our class definition to make security 
-    # assertions.
-    security = ClassSecurityInfo()
-
-    # Here is an example of a security assertion. We are 
-    # declaring that access to messageCount is public.
-    security.declarePublic('messageCount')
-
-    def messageCount(self):
-      """Return a count of messages."""
-      return len(self._messages)
-
-
-Note that in the example above we called the 'declarePublic' method
-of the 'ClassSecurityInfo' instance to declare that access to the
-'messageCount' method be public. To make security assertions for your
-object, you just call the appropriate methods of the
-'ClassSecurityInfo' object, passing the appropriate information for
-the assertion you are making.
-
-'ClassSecurityInfo' approach has a number of benefits. A major
-benefit is that it is very explicit, it allows your security
-assertions to appear in your code near the objects they protect,
-which makes it easier to assess the state of protection of your code
-at a glance. The 'ClassSecurityInfo' interface also allows you as a
-component developer to ignore the implementation details in the
-security infrastructure and protects you from future changes in those
-implementation details.
-
-Let's expand on the example above and see how to make the most common
-security assertions using the 'SecurityInfo' interface.
-
-To assert that a method is *public* (anyone may call it) you may call
-the 'declarePublic' method of the 'SecurityInfo' object, passing the
-name of the method or subobject that you are making the assertion
-on::
-
-  security.declarePublic(methodName)
-
-To assert that a method is *private* you call the 'declarePrivate'
-method of the 'SecurityInfo' object, passing the name of the method
-or subobject that you are making the assertion on::
-
-  security.declarePrivate(methodName)
-
-To assert that a method or subobject is *protected* by a particular
-permission, you call the 'declareProtected' method of the
-'SecurityInfo' object, passing a permission name and the name of a
-method to be protected by that permission::
-
-  security.declareProtected(permissionName, methodName)
-
-If you have lots of methods you want to protect under the same
-permission, you can pass as many methodNames ase you want::
-
-  security.declareProtected(permissionName, methodName1,
-  methodName2, methodName3, ...)
-
-Passing multiple names like this works for all of the 'declare'
-security methods ('declarePublic', 'declarePrivate', and
-'declareProtected').
-
-Deciding To Use 'declareProtected' vs. 'declarePublic' or 'declarePrivate'
---------------------------------------------------------------------------
-
-      If the method you're making the security declaration against is
-      innocuous, and you're confident that its execution will not
-      disclose private information nor make inappropriate changes to
-      system state, you should declare the method public.
-
-      If a method should never be run under any circumstances via
-      traversal or via through-the-web code, the method should be
-      declared private.  This is the default if a method has no
-      security assertion, so you needn't explicitly protect
-      unprotected methods unless you've used 'setDefaultAccess' to set
-      the object's default access policy to 'allow' (detailed in
-      *Other Assertions*, below).
-
-      If the method should only be executable by a certain class of
-      users, you should declare the method protected.
-
-A Class Security Example
-------------------------
-
-Let's look at an expanded version of our 'Mailbox' example that makes
-use of each of these types of security assertions::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  class Mailbox(ObjectManager):
-    """A mailbox object."""
-
-  # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    security.declareProtected('View management screens', 'manage')
-    manage=HTMLFile('mailbox_manage', globals())
-
-    security.declarePublic('messageCount')
-    def messageCount(self):
-      """Return a count of messages."""
-      return len(self._messages)
-
-    # protect 'listMessages' with the 'View Mailbox' permission
-    security.declareProtected('View Mailbox', 'listMessages')
-
-    def listMessages(self):
-      """Return a sequence of message objects."""
-      return self._messages[:]
-
-    security.declarePrivate('getMessages')
-    def getMessages(self):
-      self._messages=GoGetEm()
-      return self._messages
-
-  # call this to initialize framework classes, which
-  # does the right thing with the security assertions.
-  Globals.InitializeClass(Mailbox)
-
-Note the last line in the example.  In order for security assertions
-to be correctly applied to your class, you must call the global class
-initializer ('Globals.InitializeClass') for all classes that have
-security information. This is very important - the global initializer
-does the "dirty work" required to ensure that your object is
-protected correctly based on the security assertions that you have
-made. If you don't run it on the classes that you've protected with
-security assertions, the security assertions will not be effective.
-
-Deciding Permission Names For Protected Methods
------------------------------------------------
-
-When possible, you should make use of an existing Zope permission
-within a 'declareProtected' assertion.  A list of the permissions
-which are available in a default Zope installation is available
-within Appendix A.  When it's not possible to reuse an existing
-permission, you should choose a permission name which is a verb or a
-verb phrase.
-
-Object Assertions
------------------
-
-Often you will also want to make a security assertion on the *object
-itself*. This is important for cases where your objects may be
-accessed in a restricted environment such as DTML. Consider the
-example DTML code::
-
-  <dtml-var expr="some_method(someObject)">
-
-Here we are trying to call 'some_method', passing the object
-'someObject'. When this is evaluated in the restricted DTML
-environment, the security policy will attempt to validate access to
-both 'some_method' and 'someObject'. We've seen how to make
-assertions on methods - but in the case of 'someObject' we are not
-trying to access any particular method, but rather the *object
-itself* (to pass it to 'some_method'). Because the security machinery
-will try to validate access to 'someObject', we need a way to let the
-security machinery know how to handle access to the object itself in
-addition to protecting its methods.
-
-To make security assertions that apply to the *object itself* you
-call methods on the 'SecurityInfo' object that are analogous to the
-three that we have already seen::
-
-  security.declareObjectPublic()
-
-  security.declareObjectPrivate()
-
-  security.declareObjectProtected(permissionName)
-
-The meaning of these methods is the same as for the method variety,
-except that the assertion is made on the object itself.
-
-An Object Assertion Example
----------------------------
-
-Here is the updated 'Mailbox' example, with the addition of a
-security assertion that protects access to the object itself with the
-'View Mailbox' permission::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  class Mailbox(ObjectManager):
-    """A mailbox object."""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    # Set security for the object itself
-    security.declareObjectProtected('View Mailbox')
-
-    security.declareProtected('View management screens', 'manage')
-    manage=HTMLFile('mailbox_manage', globals())
-
-    security.declarePublic('messageCount')
-    def messageCount(self):
-      """Return a count of messages."""
-      return len(self._messages)
-
-    # protect 'listMessages' with the 'View Mailbox' permission
-    security.declareProtected('View Mailbox', 'listMessages')
-
-    def listMessages(self):
-      """Return a sequence of message objects."""
-      return self._messages[:]
-
-    security.declarePrivate('getMessages')
-    def getMessages(self):
-      self._messages=GoGetEm()
-      return self._messages
-
-  # call this to initialize framework classes, which
-  # does the right thing with the security assertions.
-  Globals.InitializeClass(Mailbox)
-
-Other Assertions
-----------------
-
-The SecurityInfo interface also supports the less common
-security assertions noted earlier in this document.
-
-To assert that access to subobjects that do not have explicit
-security information should be *allowed* rather than *denied* by
-the security policy, use::
-
-  security.setDefaultAccess("allow")
-
-This assertion should be used with caution. It will effectively
-change the access policy to "allow-by-default" for all
-attributes in your object instance (not just class attributes)
-that are not protected by explicit assertions.  By default, the
-Zope security policy flatly denies access to attributes and
-methods which are not mentioned within a security assertion.
-Setting the default access of an object to "allow" effectively
-reverses this policy, allowing access to all attributes and
-methods which are not explicitly protected by a security
-assertion.
-
-'setDefaultAccess' applies to attributes that are simple Python
-types as well as methods without explicit protection. This is
-important because some mutable Python types (lists, dicts) can
-then be modified by restricted code. Setting default access to
-"allow" also affects attributes that may be defined by the base
-classes of your class, which can lead to security holes if you
-are not sure that the attributes of your base classes are safe
-to access.
-
-Setting the default access to "allow" should only be done if you
-are sure that all of the attributes of your object are safe to
-access, since the current architecture does not support using
-explicit security assertions on non-method attributes.
-
-What Happens When You Make A Mistake Making 'SecurityInfo' Declarations?
-------------------------------------------------------------------------
-
-It's possible that you will make a mistake when making 'SecurityInfo'
-declarations.  For example, it is not legal to declare two
-conflicting permissions on a method::
-
-  class Foo(SimpleItem):
-      security = ClassSecurityInfo()
-
-      meta_type='Foo'
-
-      security.declareProtected('View foos', 'index_html')
-      def index_html(self):
-          """ make index_html web-publishable """
-          return "<html><body>hi!</body></html>"
-
-security.declareProtected('View', 'index_html')
-# whoops, declared a conflicting permission on index_html!
-
-When you make a mistake like this, the security machinery will
-accept the *first* declaration made in the code and will write
-an error to the Zope debug log upon encountering the second and
-following conflicting declarations during class initialization.
-It's similarly illegal to declare a method both private and
-public, or to declare a method both private and protected, or to
-declare a method both public and protected. A similar error will
-be raised in all of these cases.
-
-Note that Zope *will not* warn you if you misspell the name of
-a method in a declareProtected, declarePublic, or declarePrivate
-assertion.  For instance, you try to protect the 'index_html'
-method with the 'View' permission and make a mistake,
-spelling the name 'index_html' as 'inde_html', like so::
-
-  security.declareProtected('View', 'inde_html')
-  # whoops, declared a permission assertion for 'inde_html'
-  # when I really wanted it to be 'index_html'!
-  def index_html(self):
-      """ make index_html web-publishable """
-      return "<html><body>hi!</body></html>"
-
-You'll need to track down these kinds of problems yourself.
-
-Setting Default Roles For Permissions
--------------------------------------
-
-When defining operations that are protected by permissions, one thing
-you commonly want to do is to arrange for certain roles to be
-associated with a particular permission *by default* for instances of
-your object.
-
-For example, say you are creating a *News Item* object. You want
-'Anonymous' users to have the ability to view news items by default;
-you don't want the site manager to have to explicitly change the
-security settings for each *News Item* just to give the 'Anonymous"
-role 'View' permission.
-
-What you want as a programmer is a way to specify that certain roles
-should have certain permissions by default on instances of your
-object, so that your objects have sensible and useful security
-settings at the time they are created. Site managers can always
-*change* those settings if they need to, but you can make life easier
-for the site manager by setting up defaults that cover the common
-case by default.
-
-As we saw earlier, the 'SecurityInfo' interface provided a way to
-associate methods with permissions. It also provides a way to
-associate a permission with a set of default roles that should have
-that permission on instances of your object.
-
-To associate a permission with one or more roles, use the following::
-
-  security.setPermissionDefault(permissionName, rolesList)
-
-The *permissionName* argument should be the name of a permission that
-you have used in your object and *rolesList* should be a sequence
-(tuple or list) of role names that should be associated with
-*permissionName* by default on instances of your object.
-
-Note that it is not always necessary to use this method. All
-permissions for which you did not set defaults using
-'setPermissionDefault' are assumed to have a single default role of
-'Manager'.  Notable exceptions to this rule include 'View' and
-'Access contents information', which always have the default roles
-'Manager' and 'Anonymous'.
-
-The 'setPermissionDefault' method of the 'SecurityInfo' object should
-be called only once for any given permission name.
-
-
-An Example of Associating Default Roles With Permissions
---------------------------------------------------------
-
-Here is our 'Mailbox' example, updated to associate the 'View
-Mailbox' permission with the roles 'Manager' and 'Mailbox Owner' by
-default::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  class Mailbox(ObjectManager):
-    """A mailbox object."""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    # Set security for the object itself
-    security.declareObjectProtected('View Mailbox')
-
-    security.declareProtected('View management screens', 'manage')
-    manage=DTMLFile('mailbox_manage', globals())
-
-    security.declarePublic('messageCount')
-    def messageCount(self):
-      """Return a count of messages."""
-      return len(self._messages)
-
-    security.declareProtected('View Mailbox', 'listMessages')
-    def listMessages(self):
-      """Return a sequence of message objects."""
-      return self._messages[:]
-
-    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
-
-  # call this to initialize framework classes, which
-  # does the right thing with the security assertions.
-  Globals.InitializeClass(Mailbox)
-
-What Happens When You Make A Mistake Declaring Default Roles?
--------------------------------------------------------------
-
-It's possible that you will make a mistake when making default roles
-declarations.  For example, it is not legal to declare two
-conflicting default roles for a permission::
-
-  class Foo(SimpleItem):
-      security = ClassSecurityInfo()
-
-      meta_type='Foo'
-
-      security.declareProtected('View foos', 'index_html')
-      def index_html(self):
-          """ """
-          return "<html><body>hi!</body></html>"
-
-      security.setPermissionDefault('View foos', ('Manager',))
-
-      security.setPermissionDefault('View foos', ('Anonymous',))
-      # whoops, conflicting permission defaults!
-
-When you make a mistake like this, the security machinery will accept
-the *first* declaration made in the code and will write an error to
-the Zope debug log about the second and following conflicting
-declarations upon class initialization.
-
-What Can (And Cannot) Be Protected By Class Security Info?
-----------------------------------------------------------
-
-It is important to note what can and cannot be protected using the
-'ClassSecurityInfo' interface. First, the security policy relies on
-*Acquisition* to aggregate access control information, so any class
-that needs to work in the security policy must have either
-'Acquisition.Implicit' or 'Acquisition.Explicit' in its base class
-hierarchy.
-
-The current security policy supports protection of methods and
-protection of subobjects that are instances. It does *not* currently
-support protection of simple attributes of basic Python types
-(strings, ints, lists, dictionaries). For instance::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  # We subclass ObjectManager, which has Acquisition in its
-  # base class hierarchy, so we can use SecurityInfo.
-
-  class MyClass(ObjectManager):
-    """example class"""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    # Set security for the object itself
-    security.declareObjectProtected('View')
-
-    # This is ok, because subObject is an instance
-    security.declareProtected('View management screens', 'subObject')
-    subObject=MySubObject()
-
-    # This is ok, because sayHello is a method
-    security.declarePublic('sayHello')
-    def sayHello(self):
-      """Return a greeting."""
-      return "hello!"
-
-    # This will not work, because foobar is not a method
-    # or an instance - it is a standard Python type
-    security.declarePublic('foobar')
-    foobar='some string'
-
-Keep this in mind when designing your classes. If you need simple
-attributes of your objects to be accessible (say via DTML), then you
-need to use the 'setDefaultAccess' method of 'SecurityInfo' in your
-class to allow this (see the note above about the security
-implications of this). In general, it is always best to expose the
-functionality of your objects through methods rather than exposing
-attributes directly.
-
-Note also that the actual 'ClassSecurityInfo' instance you use to
-make security assertions is implemented such that it is *never*
-accessible from restricted code or through the Web (no action on the
-part of the programmer is required to protect it).
-
-Inheritance And Class Security Declarations
--------------------------------------------
-
-Python inheritance can prove confusing in the face of security
-declarations.
-
-If a base class which has already been run through "InitializeClass"
-is inherited by a superclass, nothing special needs to be done to
-protect the base class' methods within the superclass unless you wish
-to modify the declarations made in the base class.  The security
-declarations "filter down" into the superclass.
-
-On the other hand, if a base class hasn't been run through the global
-class initializer ('InitializeClass'), you need to proxy its security
-declarations in the superclass if you wish to access any of its
-methods within through-the-web code or via URL traversal.
-
-In other words, security declarations that you make using
-'ClassSecurityInfo' objects effect instances of the class upon which
-you make the declaration. You only need to make security declarations
-for the methods and subobjects that your class actually *defines*. If
-your class inherits from other classes, the methods of the base
-classes are protected by the security declarations made in the base
-classes themselves. The only time you would need to make a security
-declaration about an object defined by a base class is if you needed
-to *redefine* the security information in a base class for instances
-of your own class. An example below redefines a security assertion in
-a subclass::
-
-  from AccessControl import ClassSecurityInfo
-  import Globals
-
-  class MailboxBase(ObjectManager):
-    """A mailbox base class."""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    security.declareProtected('View Mailbox', 'listMessages')
-    def listMessages(self):
-      """Return a sequence of message objects."""
-      return self._messages[:]
-
-    security.setPermissionDefault('View Mailbox', ('Manager', 'Mailbox Owner'))
-
-  Globals.InitializeClass(MailboxBase)
-
-  class MyMailbox(MailboxBase):
-    """A mailbox subclass, where we want the security for 
-      listMessages to be public instead of protected (as 
-      defined in the base class)."""
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-
-    security.declarePublic('listMessages')
-
-  Globals.InitializeClass(MyMailbox)
-
-Class Security Assertions In Non-Product Code (External Methods/Python Scripts)
--------------------------------------------------------------------------------
-
-Objects that are returned from Python Scripts or External Methods
-need to have assertions declared for themselves before they can be
-used in restricted code.  For example, assume you have an External
-Method that returns instances of a custom 'Book' class. If you want
-to call this External Method from DTML, and you'd like your DTML to
-be able to use the returned 'Book' instances, you will need to ensure
-that your class supports Acquisition, and you'll need to make
-security assertions on the 'Book' class and initialize it with the
-global class initializer (just as you would with a class defined in a
-Product). For example::
-
-  # an external method that returns Book instances
-
-  from AccessControl import ClassSecurityInfo
-  from Acquisition import Implicit
-  import Globals
-
-  class Book(Implicit):
-
-    def __init__(self, title):
-      self._title=title
-
-    # Create a SecurityInfo for this class
-    security = ClassSecurityInfo()
-    security.declareObjectPublic()
-
-    security.declarePublic('getTitle')
-    def getTitle(self):
-      return self._title
-
-  Globals.InitializeClass(Book)
-
-  # The actual external method
-  def GetBooks(self):
-    books=[]
-    books.append(Book('King Lear').__of__(self))
-    books.append(Book('Romeo and Juliet').__of__(self))
-    books.append(Book('The Tempest').__of__(self))
-    return books
-
-Note that we *wrap* the book instances by way of their __of__ methods
-to obtain a security context before returning them.
-
-Note that this particular example is slightly dangerous.  You need to
-be careful that classes defined in external methods not be made
-persistent, as this can cause Zope object database inconsistencies.
-In terms of this example, this would mean that you would need to be
-careful to not attach the Book object returned from the 'GetBook'
-method to a persistent object within the ZODB. See Chapter 4, "ZODB
-Persistent Components" for more information.  Thus it's generally a
-good idea to define the Book class in a Product if you want books to
-be persistent.  It's also less confusing to have all of your security
-declarations in Products.
-
-However, one benefit of the 'SecurityInfo' approach is that it is
-relatively easy to subclass and add security info to classes that you
-did not write. For example, in an External Method, you may want to
-return instances of 'Book' although 'Book' is defined in another
-module out of your direct control. You can still use 'SecurityInfo'
-to define security information for the class by using::
-
-  # an external method that returns Book instances
-
-  from AccessControl import ClassSecurityInfo
-  from Acquisition import Implicit
-  import bookstuff
-  import Globals
-
-  class Book(Implicit, bookstuff.Book):
-    security = ClassSecurityInfo()
-    security.declareObjectPublic()
-    security.declarePublic('getTitle')
-
-  Globals.InitializeClass(Book)
-
-  # The actual external method
-  def GetBooks(self):
-    books=[]
-    books.append(Book('King Lear'))
-    books.append(Book('Romeo and Juliet'))
-    books.append(Book('The Tempest'))
-    return books
-
-Module Security Assertions
-==========================
-
-Another kind of 'SecurityInfo' object you will use as a
-component developer is the 'ModuleSecurityInfo' object.
-
-'ModuleSecurityInfo' objects do for objects defined in modules
-what 'ClassSecurityInfo' objects do for methods defined in
-classes.  They allow module-level objects (generally functions) to
-be protected by security assertions.  This is most useful when
-attempting to allow through-the-web code to 'import' objects
-defined in a Python module.
-
-One major difference between 'ModuleSecurityInfo' objects and
-ClassSecurityInfo objects is that 'ModuleSecurityInfo' objects
-cannot be declared 'protected' by a permission.  Instead,
-ModuleSecurityInfo objects may only declare that an object is
-'public' or 'private'.  This is due to the fact that modules are
-essentially "placeless", global things, while permission
-protection depends heavily on "place" within Zope.
-
-Declaring Module Security
--------------------------
-
-In order to use a filesystem Python module from restricted code such
-as Python Scripts, the module must have Zope security declarations
-associated with functions within it.  There are a number of ways to
-make these declarations:
-
-- By embedding the security declarations in the target module.  A
-  module that is written specifically for Zope may do so, whereas a
-  module not specifically written for Zope may not be able to do so.
-
-- By creating a wrapper module and embedding security declarations
-  within it.  In many cases it is difficult, impossible, or simply
-  undesirable to edit the target module.  If the number of objects in
-  the module that you want to protect or make public is small, you
-  may wish to simply create a wrapper module.  The wrapper module
-  imports objects from the wrapped module and provides security
-  declarations for them.
-
-- By placing security declarations in a filesystem Product.
-  Filesystem Python code, such as the '__init__.py' of a Product, can
-  make security declarations on behalf of an external module.  This
-  is also known as an "external" module security info declaration.
-
-The 'ModuleSecurityInfo' class is defined in the 'AccessControl'
-package of the Zope framework.
-
-Using ModuleSecurityInfo Objects
---------------------------------
-
-  Instances of 'ModuleSecurityInfo' are used in two different
-  situations.  In embedded declarations, inside the module they
-  affect.  And in external declarations, made on behalf of a
-  module which may never be imported.
-
-Embedded ModuleSecurityInfo Declarations
-----------------------------------------
-
-An embedded ModuleSecurityInfo declaration causes an object in its
-module to be importable by through-the-web code.
-
-Here's an example of an embedded declaration::
-
-  from AccessControl import ModuleSecurityInfo
-  modulesecurity = ModuleSecurityInfo()
-  modulesecurity.declarePublic('foo')
-
-  def foo():
-      return "hello"
-      # foo
-
-  modulesecurity.apply(globals())
-
-When making embedded ModuleSecurityInfo declarations, you should
-instantiate a ModuleSecurityInfo object and assign it to a name.
-It's wise to use the recommended name 'modulesecurity' for
-consistency's sake.  You may then use the modulesecurity object's
-'declarePublic' method to declare functions inside of the current
-module as public.  Finally, appending the last line
-("modulesecurity.apply(globals())") is an important step.  It's
-necessary in order to poke the security machinery into action.  The
-above example declares the 'foo' function public.
-
-The name 'modulesecurity' is used for consistency and for the benefit
-of new component authors, who often learn from looking at other
-people's code.  You do not have to use the name 'modulesecurity' for
-the security infrastructure to recognize your assertion information,
-but it is recommended as a convention.
-
-External ModuleSecurityInfo Declarations
-----------------------------------------
-
-By creating a ModuleSecurityInfo instance with a module name
-argument, you can make declarations on behalf of a module without
-having to edit or import the module.
-
-Here's an example of an external declaration::
-
-   from AccessControl import ModuleSecurityInfo
-   # protect the 'foo' function within (yet-to-be-imported) 'foomodule'
-   ModuleSecurityInfo('foomodule').declarePublic('foo')
-
-This declaration will cause the following code to work within
-PythonScripts::
-
-   from foomodule import foo
-
-When making external ModuleSecurityInfo declarations, you needn't use
-the "modulesecurity.apply(globals())" idiom demonstrated in the
-embedded declaration section above.  As a result, you needn't assign
-the ModuleSecurityInfo object to the name 'modulesecurity'.
-
-Providing Access To A Module Contained In A Package
----------------------------------------------------
-
-Note that if you want to provide access to a module inside of a
-package which lives in your PYTHONPATH, you'll need to provide
-security declarations for *all of the the packages and sub-packages
-along the path used to access the module.*
-
-For example, assume you have a function foo, which lives inside a
-module named 'module', which lives inside a package named 'package2',
-which lives inside a package named 'package1' You might declare the
-'foo' function public via this chain of declarations::
-
-  ModuleSecurityInfo('package1').declarePublic('package2')
-  ModuleSecurityInfo('package1.package2').declarePublic('module')
-  ModuleSecurityInfo('package1.package2.module').declarePublic('foo')
-
-Note that in the code above we took the following steps:
-
-- make a ModuleSecurityInfo object for 'package1'
-
-- call the declarePublic method of the 'package1'
-  ModuleSecurityInfo object, specifying 'package2' as what
-  we're declaring public.  This allows through the web code to
-  "see" package2 inside package1.
-
-- make a ModuleSecurityInfo object for 'package1.package2'.
-
-- call the declarePublic method of the 'package1.package2'
-  ModuleSecurityInfo object, specifying 'module' as what we're
-  declaring public.  This allows through the web code to "see"
-  'package1.package2.module'.
-
-- declare 'foo' public inside the ModuleSecurityInfo for
-  'package1.package2.module'. 
-
-Through-the-web code may now perform an import ala: 'import
-package1.package2.module.foo'
-
-Beware that Zope is buggy from 2.3 to 2.5.0b3.  If you make module
-security declarations in more than one Product, only one of the
-Products' security assertions will actually take effect.  This is
-repaired in Zope 2.5.0 and beyond.
-
-Many people who use Zope will be concerned with using
-ModuleSecurityInfo to make declarations on modules which live within
-Zope's Products directory.  This is just an example of declaring
-module security on a module within a package.  Here is an example of
-using ModuleSecurityInfo to make security declarations on behalf of
-the 'CatalogError' class in the 'ZCatalog.py' module.  This could be
-placed, for instance, within the any Product's '__init__.py' module::
-
-  from AccessControl import ModuleSecurityInfo
-  ModuleSecurityInfo('Products').declarePublic('Catalog')
-  ModuleSecurityInfo('Products.Catalog').declarePublic('CatalogError')
-
-Declaring Module Security On Modules Implemented In C
------------------------------------------------------
-
-Certain modules, such as the standard Python 'sha' module, provide
-extension types instead of classes, as the 'sha' module is
-implemented in C. Security declarations typically cannot be added to
-extension types, so the only way to use this sort of module is to
-write a Python wrapper class, or use External Methods.
-
-Default Module Security Info Declarations
------------------------------------------
-
-Through-the-web Python Scripts are by default able to import a small
-number of Python modules for which there are security
-declarations. These include 'string', 'math', and 'random'. The only
-way to make other Python modules available for import is to add
-security declarations to them in the filesystem.
-
-Utility Functions For Allowing Import of Modules By Through The Web Code
-------------------------------------------------------------------------
-
-Instead of manually providing security declarations for each function
-in a module, the utility function "allow_class" and "allow_module"
-have been created to help you declare the entire contents of a class
-or module as public.
-
-You can handle a module, such as base64, that contains only safe
-functions by writing 'allow_module("module_name")'.  For instance::
-
-  from Products.PythonScripts.Utility import allow_module
-  allow_module("base64")
-
-This statement declares all functions in the 'base64' module (
-'encode', 'decode', 'encodestring', and 'decodestring' ) as public,
-and from a script you will now be able to perform an import statement
-such as "from base64 import encodestring".
-
-
-To allow access to only some names in a module, you can eschew the
-allow_class and allow_module functions for the lessons you learned in
-the previous section and do the protection "manually"::
-
-  from AccessControl import ModuleSecurityInfo
-  ModuleSecurityInfo('module_name').declarePublic('name1','name2', ...)
-
-Making Permission Assertions On A Constructor
----------------------------------------------
-
-When you develop a Python disk-based product, you will generally be
-required to make "constructor" methods for the objects which you wish
-to make accessible via the Zope management interface by users of your
-Product.  These constructors are usually defined within the modules
-which contain classes which are intended to be turned into Zope
-instances.  For more information on how constructors are used in Zope
-with security, see Chapter 3 "Zope Products".
-
-The Zope Product machinery "bootstraps" Product-based classes with
-proper constructors into the namespace of the Zope management
-interface "Add" list at Zope startup time.  This is done as a
-consequence of registering a class by way of the Product's
-'__init__.py' 'intialize' function.  If you want to make, for
-example, the imaginary 'FooClass' in your Product available from the
-"Add" list, you may construct an '__init__.py' file that looks much
-like this::
-
-      from FooProduct import FooClass
-
-      def initialize(context):
-          """ Initialize classes in the FooProduct module """
-          context.registerClass(
-              FooProduct.FooClass, # the class object
-              permission='Add FooClasses',
-              constructors=(FooProduct.manage_addFooClassForm,
-                            FooProduct.manage_addFooClass),
-              icon='foo.gif'
-              )
-
-The line of primary concern to us above is the one which says
-"permission='Add FooClasses'".  This is a permission declaration
-which, thanks to Zope product initialization, restricts the adding of
-FooClasses to those users who have the 'Add FooClasses' permission by
-way of a role association determined by the system administrator.
-
-If you do not include a 'permission' argument to 'registerClass',
-then Zope will create a default permission named 'Add [meta-type]s'.
-So, for example, if your object had a meta_type of 'Animal', then
-Zope would create a default permission, 'Add Animals'.  For the most
-part, it is much better to be explicit then to rely on Zope to take
-care of security details for you, so be sure to specify a permission
-for your object.
-
-Designing For Security
-======================
-
-"Security is hard." -- Jim Fulton.
-
-When you're under a deadline, and you "just want it to work", dealing
-with security can be difficult.  As a component developer, following
-these basic guidelines will go a long way toward avoiding problems
-with security integration. They also make a good debugging checklist!
-
-- Ensure that any class that needs to work with security has
-  'Acquisition.Implicit' or 'Acquisition.Explicit' somewhere in its
-  base class hierarchy.
-
-- Design the interface to your objects around methods; don't expect
-  clients to access instance attributes directly.
-
-- Ensure that all methods meant for use by restricted code have been
-  protected with appropriate security assertions.
-
-- Ensure that you called the global class initializer on all classes
-  that need to work with security.
-
-Compatibility
-=============
-
-The implementation of the security assertions and 'SecurityInfo'
-interfaces described in this document are available in Zope 2.3 and
-higher.
-
-Older Zope Products do not use the 'SecurityInfo' interfaces for
-security assertions, because these interfaces didn't exist at the
-time.  These Zope products will continue to work without modification
-until further notice.
-
-Using The RoleManager Base Class With Your Zope Product
-=======================================================
-
-After your Product is deployed, system managers and other users of
-your Product often must deal with security settings on instances they
-make from your classes.
-
-Product classes which inherit Zope's standard RoleManager base class
-allow instances of the class to present a security interface.  This
-security interface allows managers and developers of a site to
-control an instance's security settings via the Zope management
-interface.
-
-The user interface is exposed via the *Security* management view.
-From this view, a system administrator may secure instances of your
-Product's class by associating roles with permissions and by
-asserting that your object instance contains "local roles".  It also
-allows them to create "user-defined roles" within the Zope management
-framework in order to associate these roles with the permissions of
-your product and with users.  This user interface and its usage
-patterns are explained in more detail within the Zope Book's security
-chapter.
-
-If your Product's class does not inherit from 'RoleManager', its
-methods will still retain the security assertions associated with
-them, but you will be unable to allow users to associate roles with
-the permissions you've defined respective to instances of your class.
-Your objects will also not allow local role definitions.  Note that
-objects which inherit from the 'SimpleItem.SimpleItem' mixin class
-already inherit from 'RoleManager'.
-
-Conclusion
-==========
-
-Zope security is based upon roles and permissions. Users have
-roles. Security policies map permissions to roles. Classes protect
-methods with permissions. As a developer you main job is to protect
-your classes by associating methods with permissions. Of course there
-are many other details such as protecting modules and functions,
-creating security user interfaces, and initializing security
-settings.

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/TestingAndDebugging.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/TestingAndDebugging.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/TestingAndDebugging.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,800 +0,0 @@
-#####################
-Testing and Debugging
-#####################
-
-As you develop Zope applications you may run into problems.  This
-chapter covers debugging and testing techniques that can help you.
-The Zope debugger allow you to peek inside a running process and find
-exactly what is going wrong.  Unit testing allows you to automate the
-testing process to ensure that your code still works correctly as you
-change it.  Finally, Zope provides logging facilities which allow you
-to emit warnings and error messages.
-
-
-Debugging
-=========
-
-Zope provides debugging information through a number of sources.  It
-also allows you a couple avenues for getting information about Zope
-as it runs.
-
-The Control Panel
------------------
-
-The control panel provides a number of views that can help you debug
-Zope, especially in the area of performance.  The *Debugging
-Information* link on the control panel provides two views, *Debugging
-Info* and *Profiling*.
-
-Debugging info provides information on the number of object
-references and the status of open requests.  The object references
-list displays the name of the object and the number of references to
-that object in Zope.  Understanding how reference counts help
-debugging is a lengthy subject, but in general you can spot memory
-leaks in your application if the number of references to certain
-objects increases without bound.  The busier your site is, or the
-more content it holds, the more reference counts you will tend to
-have.
-
-Profiling uses the standard Python profiler.  This is turned on by
-setting the 'PROFILE_PUBLISHER' environment variable before executing
-Zope.
-
-When the profiler is running, the performance of your Zope system
-will suffer a lot.  Profiling should only be used for short periods
-of time, or on a separate ZEO client so that your normal users to not
-experience this significant penalty.
-
-Profiling provides you with information about which methods in your
-Zope system are taking the most time to execute.  It builds a
-*profile*, which lists the busiest methods on your system, sorted by
-increasing resource usage.  For details on the meaning of the
-profiler's output, read the `standard Python documentation
-<http://www.python.org/doc/current/lib/profile.html>`_
-
-Product Refresh Settings
-------------------------
-
-As of Zope 2.4 there is a *Refresh* view on all Control Panel
-Products.  Refresh allows you to reload your product's modules as you
-change them, rather than having to restart Zope to see your changes.
-The *Refresh* view provides the same debugging functionality
-previously provided by Shane Hathaway's Refresh Product.
-
-To turn on product refresh capabilities place a 'refresh.txt' file in
-your product's directory.  Then visit the *Refresh* view of your
-product in the management interface.  Here you can manually reload
-your product's modules with the *Refresh this product* button.  This
-allows you to immediately see the effect of your changes, without
-restarting Zope.  You can also turn on automatic refreshing which
-causes Zope to frequently check for changes to your modules and
-refresh your product when it detects that your files have changed.
-Since automatic refresh causes Zope to run more slowly, it is a good
-idea to only turn it on for a few products at a time.
-
-Debug Mode
-----------
-
-Setting the 'Z_DEBUG_MODE=1' environment puts Zope into debug mode.
-This mode reduces the performance of Zope a little bit.  Debug model
-has a number of wide ranging effects:
-
-- Tracebacks are shown on the browser when errors are raised.
-
-- External Methods and DTMLFile objects are checked to see if they
-  have been modified every time they are called.  If modified, they
-  are reloaded.
-
-- Zope will not fork into the background in debug mode, instead, it
-  will remain attached to the terminal that started it and the main
-  logging information will be redirected to that terminal.
-
-Normally, debug mode is set using the '-D' switch when starting Zope,
-though you can set the environment variable directly if you wish.
-
-By using debug mode and product refresh together you will have little
-reason to restart Zope while developing.
-
-The Python Debugger
--------------------
-
-Zope is integrated with the Python debugger (pdb).  The Python
-debugger is pretty simple as command line debuggers go, and anyone
-familiar with other popular command line debuggers (like gdb) will
-feel right at home in pdb.
-
-For an introduction to pdb see the standard `pdb documentation
-<http://www.python.org/doc/current/lib/module-pdb.html>`_ .
-
-There are a number of ways to debug a Zope process:
-
-  o You can shut down the Zope server and simulate a request on the
-    command line.
-
-  o You can run a special ZEO client that debugs a running server.
-
-  o You can run Zope in debug model and enter the debugger
-    through Zope's terminal session.
-
-The first method is an easy way to debug Zope if you are not running
-ZEO.  First, you must first shut down the Zope process.  It is not
-possible to debug Zope in this way and run it at the same time.
-Starting up the debugger this way will by default start Zope in
-single threaded mode.
-
-For most Zope developer's purposes, the debugger is needed to debug
-some sort of application level programming error.  A common scenario
-is when developing a new product for Zope.  Products extend Zope's
-functionality but they also present the same kind of debugging
-problems that are commonly found in any programming environment.  It
-is useful to have an existing debugging infrastructure to help you
-jump immediately to your new object and debug it and play with it
-directly in pdb.  The Zope debugger lets you do this.
-
-In reality, the "Zope" part of the Zope debugger is actually just a
-handy way to start up Zope with some pre-configured break points and
-to tell the Python debugger where in Zope you want to start
-debugging.
-
-Simulating HTTP Requests
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Now for an example. Remember, for this example to work, you *must*
-shut down Zope.  Go to your Zope's 'lib/python' directory and fire up
-Python and import 'Zope' and 'ZPublisher'::
-
-  $ cd lib/python
-  $ python
-  Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
-  Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
-  >>> import Zope, ZPublisher
-  >>>
-
-Here you have run the Python interpreter (which is where using the
-debugger takes place) and imported two modules, 'Zope' and
-'ZPublisher'.  If Python complains about an 'ImportError' and not
-being able to find either module, then you are probably in the wrong
-directory, or you have not compiled Zope properly.  If you get this
-message::
-
-  ZODB.POSException.StorageSystemError: Could not lock the database
-  file.  There must be another process that has opened the file.
-
-This tells you that Zope is currently running.  Shutdown Zope and try
-again.
-
-The 'Zope' module is the main Zope application module.  When you
-import 'Zope' it sets up Zope.  'ZPublisher' is the Zope ORB.  See
-Chapter 2 for more information about 'ZPublisher'.
-
-You can use the 'ZPublisher.Zope' function to simulate an HTTP
-request.  Pass the function a URL relative the your root Zope object.
-Here is an example of how to simulate an HTTP request from the
-debugger::
-
-  >>> ZPublisher.Zope('')
-  Status: 200 OK
-  X-Powered-By: Zope (www.zope.org), Python (www.python.org)
-  Content-Length: 1238
-  Content-Type: text/html
-
-  <HTML><HEAD><TITLE>Zope</TITLE>
-
-    ... blah blah...
-
-  </BODY></HTML>
-  >>> 
-
-If you look closely, you will see that the content returned is
-*exactly* what is returned when you call your root level object
-through HTTP, including all the HTTP headers.
-
-Keep in mind that calling Zope this way does NOT involve a web
-server.  No ports are opened, the 'ZServer' code is not even
-imported.  In fact, this is just an interpreter front end to the same
-application code the ZServer *does* call.
-
-Interactive Debugging
-~~~~~~~~~~~~~~~~~~~~~
-
-Debugging involves publishing a request up to a point where you think
-it's failing, and then inspecting the state of your variables and
-objects.  The easy part is the actual inspection, the hard part is
-getting your program to stop at the right point.
-
-So, for the sake our example, let's say that you have a 'News' object
-which is defined in a Zope Product called 'ZopeNews', and is located
-in the 'lib/python/Products/ZopeNews' directory.  The class that
-defines the 'News' instance is also called 'News', and is defined in
-the 'News.py' module in your product.
-
-Therefore, from Zope's perspective the fully qualified name of your
-class is 'Products.ZopeNews.News.News'.  All Zope objects have this
-kind of fully qualified name.  For example, the 'ZCatalog' class can
-be found in 'Products.ZCatalog.ZCatalog.ZCatalog' (The redundancy is
-because the product, module, and class are all named 'ZCatalog').
-
-Now let's create an example method to debug.  You want your news
-object to have a 'postnews' method, that posts news::
-
-  class News(...):
-
-      ...
-
-      def postnews(self, news, author="Anonymous"):
-          self.news = news
-
-      def quote(self):
-          return '%s said, "%s"' % (self.author, self.news)
-
-You may notice that there's something wrong with the 'postnews'
-method.  The method assigns 'news' to an instance variable, but it
-does nothing with 'author'.  If the 'quote' method is called, it will
-raise an 'AttributeError' when it tries to look up the name
-'self.author'.  Although this is a pretty obvious goof, we'll use it
-to illustrate using the debugger to fix it.
-
-Running the debugger is done in a very similar way to how you called
-Zope through the python interpreter before, except that you introduce
-one new argument to the call to 'Zope'::
-
-  >>> ZPublisher.Zope('/News/postnews?new=blah', d=1)
-  * Type "s<cr>c<cr>" to jump to beginning of real publishing process.
-  * Then type c<cr> to jump to the beginning of the URL traversal
-    algorithm.
-  * Then type c<cr> to jump to published object call.
-  > <string>(0)?()
-  pdb> 
-
-Here, you call Zope from the interpreter, just like before, but there
-are two differences.  First, you call the 'postnews' method with an
-argument using the URL, '/News/postnews?new=blah'.  Second, you
-provided a new argument to the Zope call, 'd=1'.  The 'd' argument,
-when true, causes Zope to fire up in the Python debugger, pdb.
-Notice how the Python prompt changed from '>>>' to 'pdb>'.  This
-indicates that you are in the debugger.
-
-When you first fire up the debugger, Zope gives you a helpful message
-that tells you how to get to your object.  To understand this
-message, it's useful to know how you have set Zope up to be debugged.
-When Zope fires up in debugger mode, there are three breakpoints set
-for you automatically (if you don't know what a breakpoint is, you
-need to read the python `debugger documentation
-<http://www.python.org/doc/current/lib/module-pdb.html>`_).
-
-The first breakpoint stops the program at the point that ZPublisher
-(the Zope ORB) tries to publish the application module (in this case,
-the application module is 'Zope').  The second breakpoint stops the
-program right before ZPublisher tries to traverse down the provided
-URL path (in this case, '/News/postnews').  The third breakpoint will
-stop the program right before ZPublisher calls the object it finds
-that matches the URL path (in this case, the 'News' object).
-
-So, the little blurb that comes up and tells you some keys to press
-is telling you these things in a terse way.  Hitting 's' will *step*
-you into the debugger, and hitting 'c' will *continue* the execution
-of the program until it hits a breakpoint.
-
-Note however that none of these breakpoints will stop the program at
-'postnews'.  To stop the debugger right there, you need to tell the
-debugger to set a new breakpoint.  Why a new breakpoint?  Because
-Zope will stop you before it traverse your objects path, it will stop
-you before it calls the object, but if you want to stop it *exactly*
-at some point in your code, then you have to be explicit.  Sometimes
-the first three breakpoints are convienent, but often you need to set
-your own special break point to get you exactly where you want to go.
-
-Setting a breakpoint is easy (and see the next section for an even
-easier method).  For example::
-
-  pdb> import Products
-  pdb> b Products.ZopeNews.News.News.postnews
-  Breakpoint 5 at C:\Program Files\WebSite\lib\python\Products\ZopeNews\News.py:42
-  pdb> 
-
-First, you import 'Products'.  Since your module is a Zope product,
-it can be found in the 'Products' package.  Next, you set a new
-breakpoint with the *break* debugger command (pdb allows you to use
-single letter commands, but you could have also used the entire word
-'break').  The breakpoint you set is
-'Products.ZopeNews.News.News.postnews'.  After setting this
-breakpoint, the debugger will respond that it found the method in
-question in a certain file, on a certain line (in this case, the
-fictitious line 42) and return you to the debugger.
-
-Now, you want to get to your 'postnews' method so you can start
-debugging it.  But along the way, you must first *continue* through
-the various breakpoints that Zope has set for you.  Although this may
-seem like a bit of a burden, it's actually quite good to get a feel
-for how Zope works internally by getting down the rhythm that Zope
-uses to publish your object.  In these next examples, my comments
-will begin with '#".  Obviously, you won't see these comments when
-you are debugging.  So let's debug::
-
-  pdb> s
-  # 's'tep into the actual debugging
-
-  > <string>(1)?()
-  # this is pdb's response to being stepped into, ignore it
-
-  pdb> c
-  # now, let's 'c'ontinue onto the next breakpoint
-
-  > C:\Program Files\WebSite\lib\python\ZPublisher\Publish.py(112)publish()
-  -> def publish(request, module_name, after_list, debug=0,
-
-  # pdb has stopped at the first breakpoint, which is the point where
-  # ZPubisher tries to publish the application module.
-
-  pdb> c
-  # continuing onto the next breakpoint you get...
-
-  > C:\Program Files\WebSite\lib\python\ZPublisher\Publish.py(101)call_object()
-  -> def call_object(object, args, request):
-
-Here, 'ZPublisher' (which is now publishing the application) has
-found your object and is about to call it.  Calling your object
-consists of applying the arguments supplied by 'ZPublisher' to the
-object.  Here, you can see how 'ZPublisher' is passing three
-arguments into this process.  The first argument is 'object' and is
-the actual object you want to call.  This can be verified by
-*printing* the object::
-
-  pdb> p object
-  <News instance at 00AFE410>
-
-Now you can inspect your object (with the *print* command) and even
-play with it a bit.  The next argument is 'args'.  This is a tuple of
-arguments that 'ZPublisher' will apply to your object call.  The
-final argument is 'request'.  This is the request object and will
-eventually be transformed in to the DTML usable object 'REQUEST'. Now
-continue, your breakpoint is next::
-
-  pdb> c    
-  > C:\Program Files\WebSite\lib\python\Products\ZopeNews\News.py(42)postnews()
-  -> def postnews(self, N)
-
-Now you are here, at your method.  To be sure, tell the debugger to
-show you where you are in the code with the 'l' command.  Now you can
-examine variable and perform all the debugging tasks that the Python
-debugger provides.  From here, with a little knowledge of the Python
-debugger, you should be able to do any kind of debugging task that is
-needed.
-
-Interactive Debugging Triggered From the Web
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you are running in debug mode you can set break points in your
-code and then jump straight to the debugger when Zope comes across
-your break points.  Here's how to set a breakpoint::
-
-  import pdb;pdb.set_trace()
-
-Now start Zope in debug mode and point your web browser at a URL that
-causes Zope to execute the method that includes a breakpoint.  When
-this code is executed, the Python debugger will come up in the
-terminal where you started Zope.  Also note that from your web
-browser it looks like Zope is frozen.  Really it's just waiting for
-you do your debugging.
-
-From the terminal you are inside the debugger as it is executing your
-request.  Be aware that you are just debugging one thread in Zope,
-and other requests may be being served by other threads.  If you go
-to the *Debugging Info* screen while in the debugger, you can see
-your debugging request and how long it has been open.
-
-It is often more convenient to use this method to enter the debugger
-than it is to call 'ZPublisher.Zope' as detailed in the last section.
-
-Post-Mortem Debugging
-~~~~~~~~~~~~~~~~~~~~~
-
-Often, you need to use the debugger to chase down obscure problems in
-your code, but sometimes, the problem is obvious, because an
-exception gets raised.  For example, consider the following method on
-your 'News' class::
-
-  def quote(self):
-      return '%s said, "%s"' % (self.Author, self.news)
-
-Here, you can see that the method tries to substitute 'self.Author'
-in a string, but earlier we saw that this should really be
-'self.author'.  If you tried to run this method from the command
-line, an exception would be raised::
-
-  >>> ZPublisher.Zope('/News/quote')
-  Traceback (most recent call last):
-    File "<stdin>", line 1, in ?
-    File "./News.py", line 4, in test
-      test2()
-    File "./News.py", line 3, in test2
-      return '%s said, "%s"' % (self.Author, self.news)
-  NameError: Author
-  >>>
-
-Using Zope's normal debugging methods, you would typically need to
-start from the "beginning" and step your way down through the
-debugger to find this error (in this case, the error is pretty
-obvious, but more often than not errors can be pretty obscure!).
-
-Post-mortem debugging allows you to jump *directly* to the spot in
-your code that raised the exception, so you do not need to go through
-the possibly tedious task of stepping your way through a sea of
-Python code.  In the case of our example, you can just pass
-'ZPublisher.Zope' call a 'pm' argument that is set to 1::
-
-          >>> ZPublisher.Zope('/News/quote', pm=1)
-          Traceback (most recent call last):
-            File "<stdin>", line 1, in ?
-            File "./News.py", line 4, in test
-              test2()
-            File "./News.py", line 3, in test2
-              return '%s said, "%s"' % (self.Author, self.news)
-          NameError: Author
-          (pdb)
-
-Here, you can see that instead of taking you back to a python prompt,
-the post mortem debugging flag has caused you to go right into the
-debugging, *exactly* at the point in your code where the exception is
-raised.  This can be verified with the debugger's (l)ist
-command. Post mortem debugging offers you a handy way to jump right
-to the section of your code that is failing in some obvious way by
-raising an exception.
-
-Debugging With ZEO
-~~~~~~~~~~~~~~~~~~
-
-ZEO presents some interesting debugging abilities.  ZEO lets you
-debug one ZEO client when other clients continue to server requests
-for your site.  In the above examples, you have to shut down Zope to
-run in the debugger, but with ZEO, you can debug a production site
-while other clients continue to serve requests. Using ZEO is beyond
-the scope of this chapter. However, once you have ZEO running, you
-can debug a client process exactly as you debug a single-process
-Zope.
-
-
-Unit Testing
-============
-
-Unit testing allows you to automatically test your classes to make
-sure they are working correctly. By using unit tests you can make
-sure as you develop and change your classes that you are not breaking
-them. Zope comes with Pyunit. You can find out more information on
-Pyunit at `the Pyunit home page <http://pyunit.sourceforge.net/>`_
-. Pyunit is also part of the Python `standard library
-<http://www.python.org/doc/lib/module-unittest.html>`_ as of Python
-2.1.
-
-
-What Are Unit Tests
--------------------
-
-A "unit" may be defined as a piece of code with a single intended
-purpose.  A "unit test" is defined as a piece of code which exists
-to codify the intended behavior of a unit and to compare its
-intended behavior against its actual behavior.
-
-Unit tests are a way for developers and quality assurance engineers
-to quickly ascertain whether independent units of code are working as
-expected.  Unit tests are generally written at the same time as the
-code they are intended to test.  A unit testing framework allows a
-collection of unit tests to be run without human intervention,
-producing a minimum of output if all the tests in the collection are
-successful.
-
-It's a good idea to have a sense of the limits of unit testing.  From
-the `Extreme Programming Enthusiast website
-<http://c2.com/cgi/wiki?UnitTestsDefined>`_ here is a list of things
-that unit tests are *not*:
-
-- Manually operated.
-
-- Automated screen-driver tests that simulate user input (these are
-  "functional tests").
-
-- Interactive.  They run "no questions asked."
-
-- Coupled.  They run without dependencies except those native to the
-  thing being tested.
-
-- Complicated.  Unit test code is typically straightforward
-  procedural code that simulates an event.
-
-Writing Unit Tests
-------------------
-
-Here are the times when you should write unit tests:
-
-* When you write new code
-
-* When you change and enhance existing code
-
-* When you fix bugs
-
-It's much better to write tests when you're working on code than to
-wait until you're all done and then write tests.
-
-You should write tests that exercise discrete "units" of
-functionality.  In other words, write simple, specific tests that
-test one capability.  A good place to start is with interfaces and
-classes.  Classes and especially interfaces already define units of
-work which you may wish to test.
-
-Since you can't possibly write tests for every single capability and
-special case, you should focus on testing the riskiest parts of your
-code.  The riskiest parts are those that would be the most disastrous
-if they failed.  You may also want to test particularly tricky or
-frequently changed things.
-
-Here's an example test script that tests the 'News' class defined
-earlier in this chapter::
-
-  import unittest
-  import News
-
-  class NewsTest(unittest.TestCase):
-
-      def testPost(self):
-          n=News()
-          s='example news'
-          n.postnews(s)
-          assert n.news==s
-
-      def testQuote(self):
-          n=News()
-          s='example news'
-          n.postnews(s)
-          assert n.quote()=='Anonymous said: "%s"' % s
-          a='Author'
-          n.postnews(s, a)
-          assert n.quote()=='%s said: "%s"' % (a, s)
-
-  def test_suite():
-     return unittest.makeSuite(NewsTest, 'news test')
-
-  def main():
-     unittest.TextTestRunner().run(test_suite())
-
-  if __name__=="__main__":
-      main()
-
-You should save tests inside a 'tests' sub-directory in your
-product's directory. Test scripts file names should start with test,
-for example 'testNews.py'. You may accumulate many test scripts in
-your product's 'tests' directory.  You can run test your product by
-running the test scripts.
-
-We cannot cover all there is to say about unit testing here. Take a
-look at the Pyunit `documentation
-<http://pyunit.sourceforge.net/pyunit.html>`_ for more background on
-unit testing.
-
-Zope Test Fixtures
-------------------
-
-One issue that you'll run into when unit testing is that you may need
-to set up a Zope environment in order to test your products.  You can
-solve this problem in two ways.  First, you can structure your
-product so that much of it can be tested without Zope (as you did in
-the last section).  Second, you can create a test fixture that sets
-up a Zope environment for testing.
-
-To create a test fixture for Zope you'll need to:
-
-1. Add Zope's 'lib/python' directory to the Python path.
-
-2. Import 'Zope' and any other needed Zope modules and packages.
-
-3. Get a Zope application object.
-
-4. Do your test using the application object.
-
-5. Clean up the test by aborting or committing the transaction and
-   closing the Zope database connection.
-
-Here's an example Zope test fixture that demonstrates how to do each
-of these steps::
-
-  import os, os.path, sys, string
-  try:
-      import unittest
-  except ImportError:
-      fix_path()
-      import unittest
-
-  class MyTest(unittest.TestCase):
-
-      def setUp(self):
-          # Get the Zope application object and store it in an
-          # instance variable for use by test methods
-          import Zope
-          self.app=Zope.app()
-
-      def tearDown(self):
-          # Abort the transaction and shut down the Zope database
-          # connection.
-          get_transaction().abort()
-          self.app._p_jar.close()
-
-      # At this point your test methods can perform tests using
-      # self.app which refers to the Zope application object.
-
-      ...
-
-  def fix_path():
-      # Add Zope's lib/python directory to the Python path
-      file=os.path.join(os.getcwd(), sys.argv[0])
-      dir=os.path.join('lib', 'python')
-      i=string.find(file, dir)
-      sys.path.insert(0, file[:i+len(dir)])
-
-  def test_suite():
-     return unittest.makeSuite(MyTest, 'my test')
-
-  def main():
-     unittest.TextTestRunner().run(test_suite())
-
-  if __name__=="__main__":
-      fix_path()
-      main()
-
-This example shows a fairly complete Zope test fixture.  If your Zope
-tests only needs to import Zope modules and packages you can skip
-getting a Zope application object and closing the database
-transaction.
-
-Some times you may run into trouble if your test assuming that there
-is a current Zope request.  There are two ways to deal with this.
-One is to use the 'makerequest' utility module to create a fake
-request.  For example::
-
-  class MyTest(unittest.TestCase):
-      ...
-
-      def setup(self):
-          import Zope
-          from Testing import makerequest
-          self.app=makerequest.makerequest(Zope.app())
-
-This will create a Zope application object that is wrapped in a
-request.  This will enable code that expects to acquire a 'REQUEST'
-attribute work correctly.
-
-Another solution to testing methods that expect a request is to use
-the 'ZPublisher.Zope' function described earlier.  Using this
-approach you can simulate HTTP requests in your unit tests.  For
-example::
-
-  import ZPublisher
-
-  class MyTest(unittest.TestCase):
-      ...
-
-      def testWebRequest(self):
-          ZPublisher.Zope('/a/url/representing/a/method?with=a&couple=arguments',
-                          u='username:password', 
-                          s=1, 
-                          e={'some':'environment', 'variable':'settings'})
-
-If the 's' argument is passed to 'ZPublisher.Zope' then no output
-will be sent to 'sys.stdout'.  If you want to capture the output of
-the publishing request and compare it to an expected value you'll
-need to do something like this::
-
-  f=StringIO()
-  temp=sys.stdout
-  sys.stdout=f
-  ZPublisher.Zope('/myobject/mymethod')
-  sys.stdout=temp
-  assert f.getvalue() == expected_output
-
-Here's a final note on unit testing with a Zope test fixture: you may
-find Zope helpful.  ZEO allows you to test an application while it
-continues to serve other users.  It also speeds Zope start up time
-which can be a big relief if you start and stop Zope frequently while
-testing.
-
-Despite all the attention we've paid to Zope testing fixtures, you
-should probably concentrate on unit tests that don't require a Zope
-test fixture.  If you can't test much without Zope there is a good
-chance that your product would benefit from some refactoring to make
-it simpler and less dependent on the Zope framework.
-
-Logging
-=======
-
-Zope provides a framework for logging information to Zope's
-application log.  You can configure Zope to write the application log
-to a file, syslog, or other back-end.
-
-The logging API defined in the 'zLOG' module.  This module provides
-the 'LOG' function which takes the following required arguments:
-
-- subsystem -- The subsystem generating the message (e.g. "ZODB")
-
-- severity -- The "severity" of the event.  This may be an integer or
-  a floating point number.  Logging back ends may consider the int()
-  of this value to be significant.  For example, a back-end may
-  consider any severity whose integer value is WARNING to be a
-  warning.
-
-- summary -- A short summary of the event
-
-These arguments to the 'LOG' function are optional:
-
-- detail -- A detailed description
-
-- error -- A three-element tuple consisting of an error type, value,
-  and traceback.  If provided, then a summary of the error is added
-  to the detail.
-
-- reraise -- If provided with a true value, then the error given by
-  error is reraised.
-
-You can use the 'LOG' function to send warning and errors to the Zope
-application log.
-
-Here's an example of how to use the 'LOG' function to write debugging
-messages::
-
-  from zLOG import LOG, DEBUG
-  LOG('my app', DEBUG, 'a debugging message')
-
-You can use 'LOG' in much the same way as you would use print
-statements to log debugging information while Zope is running.  You
-should remember that Zope can be configured to ignore log messages
-below certain levels of severity.  If you are not seeing your logging
-messages, make sure that Zope is configured to write them to the
-application log.
-
-In general the debugger is a much more powerful way to locate
-problems than using the logger.  However, for simple debugging tasks
-and for issuing warnings the logger works just fine.
-
-Other Testing and Debugging Facilities
-======================================
-
-There is a few other testing and debugging techniques and tools not
-commonly used to test Zope.  In this section we'll mention several of
-them.
-
-Debug Logging
--------------
-
-Zope provides an analysis tool for debugging log output.  This output
-allows may give you hints as to where your application may be
-performing poorly, or not responding at all.  For example, since
-writing Zope products lets your write unrestricted Python code, it's
-very possibly to get yourself in a situation where you "hang" a Zope
-request, possibly by getting into a infinite loop.
-
-To try and detect at which point your application hangs, use the
-*requestprofiler.py* script in the *utilities* directory of your Zope
-installation.  To use this script, you must run Zope with the '-M'
-command line option.  This will turn on "detailed debug logging" that
-is necessary for the *requestprofiler.py* script to run.  The
-*requestprofiler.py* script has quite a few options which you can
-learn about with the '--help' switch.
-
-In general debug log analysis should be a last resort.  Use it when
-Zope is hanging and normal debugging and profiling is not helping you
-solve your problem.
-
-HTTP Benchmarking
------------------
-
-HTTP load testing is notoriously inaccurate.  However, it is useful
-to have a sense of how many requests your server can support.  Zope
-does not come with any HTTP load testing tools, but there are many
-available.  Apache's 'ab' program is a widely used free tool that can
-load your server with HTTP requests.
-
-Summary
-=======
-
-Zope provides a number of different debugging and testing facilities.
-The debugger allows you to interactively test your applications.
-Unit tests allow help you make sure that your application is develops
-correctly.  The logger allows you to do simple debugging and issue
-warnings.

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/ZODBPersistentComponents.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/ZODBPersistentComponents.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/ZODBPersistentComponents.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,596 +0,0 @@
-##########################
-ZODB Persistent Components
-##########################
-
-Most Zope components live in the Zope Object DataBase (ZODB).
-Components that are stored in ZODB are said to be *persistent*.
-Creating persistent components is, for the most part, a trivial
-exercise, but ZODB does impose a few rules that persistent components
-must obey in order to work properly.  This chapter describes the
-persistence model and the interfaces that persistent objects can use
-to live inside the ZODB.
-
-Persistent Objects
-==================
-
-Persistent objects are Python objects that live for a long time. Most
-objects are created when a program is run and die when the program
-finishes. Persistent objects are not destroyed when the program ends,
-they are saved in a database.
-
-A great benefit of persistent objects is their transparency.  As a
-developer, you do not need to think about loading and unloading the
-state of the object from memory.  Zope's persistent machinery handles
-all of that for you.
-
-This is also a great benefit for application designers; you do not
-need to create your own kind of "data format" that gets saved to a
-file and reloaded again when your program stops and starts.  Zope's
-persistence machinery works with *any* kind of Python objects (within
-the bounds of a few simple rules) and as your types of objects grow,
-your database simply grows transparently with it.
-
-Persistence Example
--------------------
-
-Here is a simple example of using ZODB outside of Zope.  If all you
-plan on doing is using persistent objects with Zope, you can skip
-this section if you wish.
-
-The first thing you need to do to start working with ZODB is to
-create a "root object".  This process involves first opening a
-"storage" , which is the actual backend storage location for your
-data.
-
-ZODB supports many pluggable storage back-ends, but for the purposes
-of this article we're going to show you how to use the 'FileStorage'
-back-end storage, which stores your object data in a file.  Other
-storages include storing objects in relational databases, Berkeley
-databases, and a client to server storage that stores objects on a
-remote storage server.
-
-
-To set up a ZODB, you must first install it.  ZODB comes with Zope,
-so the easiest way to install ZODB is to install Zope and use the
-ZODB that comes with your Zope installation.  For those of you who
-don't want all of Zope, but just ZODB, see the instructions for
-downloading ZODB from the `ZODB web page
-<http://wiki.zope.org/ZODB>`_.
-
-After installing ZODB, you can start to experiment with it right from
-the Python command line interpreter.  If you've installed Zope,
-before running this set of commands, shut down your Zope server, and
-"cd" to the "lib/python" directory of your Zope instance.  If you're
-using a "standalone" version of ZODB, you likely don't need to do
-this, and you'll be able to use ZODB by importing it from a standard
-Python package directory.  In either case, try the following set of
-commands::
-
-  chrism at saints:/opt/zope/lib/python$ python
-  Python 2.1.1 (#1, Aug  8 2001, 21:17:50) 
-  [GCC 2.95.2 20000220 (Debian GNU/Linux)] on linux2
-  Type "copyright", "credits" or "license" for more information. 
-  >>> from ZODB import FileStorage, DB
-  >>> storage = FileStorage.FileStorage('mydatabase.fs')
-  >>> db = DB( storage )
-  >>> connection = db.open()
-  >>> root = connection.root()
-
-Here, you create storage and use the 'mydatabse.fs' file to store the
-object information.  Then, you create a database that uses that
-storage.
-
-
-Next, the database needs to be "opened" by calling the 'open()'
-method.  This will return a connection object to the database.  The
-connection object then gives you access to the 'root' of the database
-with the 'root()' method.
-
-The 'root' object is the dictionary that holds all of your persistent
-objects.  For example, you can store a simple list of strings in the
-root object::
-
-      root['employees'] = ['Bob', 'Mary', 'Jo']
-
-Now, you have changed the persistent database by adding a new object,
-but this change is so far only temporary.  In order to make the
-change permanent, you must commit the current transaction::
-
-      get_transaction().commit()
-
-Transactions are ways to make a lot of changes in one atomic
-operation.  In a later article, we'll show you how this is a very
-powerful feature.  For now, you can think of committing transactions
-as "checkpoints" where you save the changes you've made to your
-objects so far.  Later on, we'll show you how to abort those changes,
-and how to undo them after they are committed.
-
-If you had used a relational database, you would have had to issue a
-SQL query to save even a simple python list like the above example.
-You would have also needed some code to convert a SQL query back into
-the list when you wanted to use it again.  You don't have to do any
-of this work when using ZODB.  Using ZODB is almost completely
-transparent, in fact, ZODB based programs often look suspiciously
-simple!
-
-Working with simple python types is useful, but the real power of
-ZODB comes out when you store your own kinds of objects in the
-database.  For example, consider a class that represents a employee::
-
-  from Persistence import Persistent
-
-  class Employee(Persistent):
-
-      def setName(self, name):
-          self.name = name
-
-
-Calling 'setName' will set a name for the employee.  Now, you can put
-Employee objects in your database::
-
-  for name in ['Bob', 'Mary', 'Joe']:
-      employee = Employee()
-      employee.setName(name)
-      root['employees'].append(employee)
-
-  get_transaction().commit()
-
-Don't forget to call 'commit()', so that the changes you have made so
-far are committed to the database, and a new transaction is begun.
-
-Persistent Rules
-================
-
-There are a few rules that must be followed when your objects are
-persistent.
-
-- Your objects, and their attributes, must be "pickleable".
-
-- Your object cannot have any attributes that begin with '_p_'.
-
-- Attributes of your object that begin with '_v_' are "volatile" and
-  are not saved to the database (see next section).
-
-- You must explicitly signal any changes made to mutable attributes
-  (such as instances, lists, and dictionaries) or use persistent
-  versions of mutable objects, like 'ZODB.PersistentMapping' (see
-  below for more information on 'PersistentMapping'.)
-
-In this section, we'll look at each of these special rules one by
-one.
-
-The first rules says that your objects must be pickleable.  This
-means that they can be serialized into a data format with the
-"pickle" module.  Most python data types (numbers, lists,
-dictionaries) can be pickled.  Code objects (method, functions,
-classes) and file objects (files, sockets) *cannot* be pickled.
-Instances can be persistent objects if:
-
-- They subclass 'Persistence.Persistent'
-
-- All of their attributes are pickleable
-
-The second rule is that none of your objects attributes can begin
-with '_p_'.  For example, '_p_b_and_j' would be an illegal object
-attribute.  This is because the persistence machinery reserves all of
-these names for its own purposes.
-
-The third rule is that all object attributes that begin with '_v_'
-are "volatile" and are not saved to the database.  This means that as
-long as the persistent object is in Zope memory cache, volatile
-attributes can be used.  When the object is deactivated (removed from
-memory) volatile attributes are thrown away.
-
-Volatile attributes are useful for data that is good to cache for a
-while but can often be thrown away and easily recreated.  File
-connections, cached calculations, rendered templates, all of these
-kinds of things are useful applications of volatile attributes. You
-must exercise care when using volatile attributes.  Since you have
-little control over when your objects are moved in and out of memory,
-you never know when your volatile attributes may disappear.
-
-The fourth rule is that you must signal changes to mutable types.
-This is because persistent objects can't detect when mutable types
-change, and therefore, doesn't know whether or not to save the
-persistent object or not.
-
-For example, say you had a list of names as an attribute of your
-object called 'departments' that you changed in a method called
-'addDepartment'::
-
-  class DepartmentManager(Persistent):
-
-      def __init__(self):
-          self.departments = []
-
-      def addDepartment(self, department):
-          self.departments.append(department)
-
-When you call the 'addDepartment' method you change a mutable type,
-'departments' but your persistent object will not save that change.
-
-There are two solutions to this problem.  First, you can assign a
-special flag, '_p_changed'::
-
-  def addDepartment(self, department):
-      self.department.append(department)
-      self._p_changed = 1
-
-Remember, '_p_' attributes do something special to the persistence
-machinery and are reserved names. Assigning 1 to '_p_changed' tells
-the persistence machinery that you changed the object, and that it
-should be saved.
-
-Another technique is to use the mutable attribute as though it were
-immutable. In other words, after you make changes to a mutable
-object, reassign it::
-
-  def addDepartment(self, department):
-      departments = self.departments
-      departments.append(department)
-      self.department = departments
-
-Here, the 'self.departments' attribute was re-assigned at the end of
-the function to the "working copy" object 'departments'.  This
-technique is cleaner because it doesn't have any explicit
-'_p_changed' settings in it, but this implicit triggering of the
-persistence machinery should always be understood, otherwise use the
-explicit syntax.
-
-A final option is to use persistence-aware mutable attributes such as
-'PersistentMapping', and 'IOBTree'. 'PersistentMapping' is a mapping
-class that notifies ZODB when you change the mapping. You can use
-instances of 'PersistentMapping' in place of standard Python
-dictionaries and not worry about signaling change by reassigning the
-attribute or using '_p_changed'. Zope's Btree classes are also
-persistent-aware mutable containers. This solution can be cleaner
-than using mutable objects immutably, or signaling change manually
-assuming that there is a persistence-aware class available that meets
-your needs.
-
-Transactions and Persistent Objects
-===================================
-
-When changes are saved to ZODB, they are saved in a *transaction*.
-This means that either all changes are saved, or none are saved.  The
-reason for this is data consistency.  Imagine the following scenario:
-
-1. A user makes a credit card purchase at the sandwich.com website.
-
-2. The bank debits their account.
-
-3. An electronic payment is made to sandwich.com.
-
-Now imagine that an error happens during the last step of this
-process, sending the payment to sandwich.com.  Without transactions,
-this means that the account was debited, but the payment never went
-to sandwich.com!  Obviously this is a bad situation.  A better
-solution is to make all changes in a transaction:
-
-1. A user makes a credit card purchase at the sandwich.com website.
-
-2. The transaction begins
-
-3. The bank debits their account.
-
-4. An electronic payment is made to sandwich.com.
-
-5. The transaction commits
-
-Now, if an error is raised anywhere between steps 2 and 5, *all*
-changes made are thrown away, so if the payment fails to go to
-sandwich.com, the account won't be debited, and if debiting the
-account raises an error, the payment won't be made to sandwich.com,
-so your data is always consistent.
-
-When using your persistent objects with Zope, Zope will automatically
-*begin* a transaction when a web request is made, and *commit* the
-transaction when the request is finished.  If an error occurs at any
-time during that request, then the transaction is *aborted*, meaning
-all the changes made are thrown away.
-
-If you want to *intentionally* abort a transaction in the middle of a
-request, then just raise an error at any time.  For example, this
-snippet of Python will raise an error and cause the transaction to
-abort::
-
-  raise SandwichError('Not enough peanut butter.')
-
-A more likely scenario is that your code will raise an exception when
-a problem arises. The great thing about transactions is that you
-don't have to include cleanup code to catch exceptions and undo
-everything you've done up to that point. Since the transaction is
-aborted the changes made in the transaction will not be saved.
-
-Because Zope does transaction management for you, most of the time
-you do not need to explicitly begin, commit or abort your own
-transactions.  For more information on doing transaction management
-manually, see the links at the end of this chapter that lead to more
-detailed tutorials of doing your own ZODB programming.
-
-
-Subtransactions
----------------
-
-Zope waits until the transaction is committed to save all the changes
-to your objects.  This means that the changes are saved in memory.
-If you try to change more objects than you have memory in your
-computer, your computer will begin to swap and thrash, and maybe even
-run you out of memory completely.  This is bad. The easiest solution
-to this problem is to not change huge quantities of data in one
-transaction.
-
-If you need to spread a transaction out of lots of data, however, you
-can use subtransactions.  Subtransactions allow you to manage Zope's
-memory usage yourself, so as to avoid swapping during large
-transactions.
-
-Subtransactions allow you to make huge transactions. Rather than
-being limited by available memory, you are limited by available disk
-space.  Each subtransaction commit writes the current changes out to
-disk and frees memory to make room for more changes.
-
-To commit a subtransaction, you first need to get a hold of a
-transaction object.  Zope adds a function to get the transaction
-objects in your global namespace, 'get_transaction', and then call
-'commit(1)' on the transaction::
-
-  get_transaction().commit(1)
-
-You must balance speed, memory, and temporary storage concerns when
-deciding how frequently to commit subtransactions. The more
-subtransactions, the less memory used, the slower the operation, and
-the more temporary space used. Here's and example of how you might
-use subtransactions in your Zope code::
-
-  tasks_per_subtransaction = 10
-  i = 0
-  for task in tasks:
-      process(task)
-      i = i + 1
-      if i % tasks_per_subtransaction == 0:
-          get_transaction().commit(1)
-
-This example shows how to commit a subtransaction at regular
-intervals while processing a number of tasks.
-
-Threads and Conflict Errors
----------------------------
-
-Zope is a multi-threaded server.  This means that many different
-clients may be executing your Python code in different threads.  For
-most cases, this is not an issue and you don't need to worry about
-it, but there are a few cases you should look out for.
-
-The first case involves threads making lots of changes to objects and
-writing to the database.  The way ZODB and threading works is that
-each thread that uses the database gets its own *connection* to the
-database.  Each connection gets its own *copy* of your object.  All
-of the threads can read and change any of the objects.  ZODB keeps
-all of these objects synchronized between the threads. The upshot is
-that you don't have to do any locking or thread synchronization
-yourself. Your code can act as though it is single threaded.
-
-However, synchronization problems can occur when objects are changed
-by two different threads at the same time.
-
-Imagine that thread 1 gets its own copy of object A, as does thread
-2.  If thread 1 changes its copy of A, then thread 2 will not see
-those changes until thread 1 commits them.  In cases where lots of
-objects are changing, this can cause thread 1 and 2 to try and commit
-changes to object 1 at the same time.
-
-When this happens, ZODB lets one transaction do the commit (it
-"wins") and raises a 'ConflictError' in the other thread (which
-"looses"). The looser can elect to try again, but this may raise yet
-another 'ConflictError' if many threads are trying to change object
-A. Zope does all of its own transaction management and will retry a
-losing transaction three times before giving up and raising the
-'ConflictError' all the way up to the user.
-
-
-Resolving Conflicts
--------------------
-
-If a conflict happens, you have two choices. The first choice is that
-you live with the error and you try again. Statistically, conflicts
-are going to happen, but only in situations where objects are
-"hot-spots".  Most problems like this can be "designed away"; if you
-can redesign your application so that the changes get spread around
-to many different objects then you can usually get rid of the hot
-spot.
-
-
-Your second choice is to try and *resolve* the conflict. In many
-situations, this can be done. For example, consider the following
-persistent object::
-
-  class Counter(Persistent):
-
-      self.count = 0
-
-      def hit(self):
-          self.count = self.count + 1
-
-This is a simple counter.  If you hit this counter with a lot of
-requests though, it will cause conflict errors as different threads
-try to change the count attribute simultaneously.
-
-But resolving the conflict between conflicting threads in this case
-is easy.  Both threads want to increment the self.count attribute by
-a value, so the resolution is to increment the attribute by the sum
-of the two values and make both commits happy; no 'ConflictError' is
-raised.
-
-
-To resolve a conflict, a class should define an '_p_resolveConflict'
-method. This method takes three arguments.
-
-'oldState' -- The state of the object that the changes made by the
-current transaction were based on. The method is permitted to modify
-this value.
-
-'savedState' -- The state of the object that is currently stored in
-the database. This state was written after 'oldState' and reflects
-changes made by a transaction that committed before the current
-transaction. The method is permitted to modify this value.
-
-'newState' -- The state after changes made by the current
-transaction.  The method is *not* permitted to modify this
-value. This method should compute a new state by merging changes
-reflected in 'savedState' and 'newState', relative to 'oldState'.
-
-The method should return the state of the object after resolving the
-differences.
-
-Here is an example of a '_p_resolveConflict' in the 'Counter' class::
-
-  class Counter(Persistent):
-
-      self.count = 0
-
-      def hit(self):
-          self.count = self.count + 1
-
-      def _p_resolveConflict(self, oldState, savedState, newState):
-
-          # Figure out how each state is different:
-          savedDiff= savedState['count'] - oldState['count']
-          newDiff= newState['count']- oldState['count']
-
-          # Apply both sets of changes to old state:
-          oldState['count'] = oldState['count'] + savedDiff + newDiff
-
-          return oldState
-
-In the above example, '_p_resolveConflict' resolves the difference
-between the two conflicting transactions.
-
-Threadsafety of Non-Persistent Objects
-======================================
-
-ZODB takes care of threadsafety for persistent objects. However, you
-must handle threadsafey yourself for non-persistent objects which are
-shared between threads.
-
-Mutable Default Arguments
--------------------------
-
-One tricky type of non-persistent, shared objects are mutable default
-arguments to functions, and methods.  Default arguments are useful
-because they are cached for speed, and do not need to be recreated
-every time the method is called.  But if these cached default
-arguments are mutable, one thread may change (mutate) the object when
-another thread is using it, and that can be bad.  So, code like::
-
-        def foo(bar=[]):
-            bar.append('something')
-
-
-Could get in trouble if two threads execute this code because lists
-are mutable.  There are two solutions to this problem:
-
-- Don't use mutable default arguments. (Good)
-
-- If you use them, you cannot change them.  If you want to change
-  them, you will need to implement your own locking. (Bad)
-
-We recommend the first solution because mutable default arguments are
-confusing, generally a bad idea in the first place.
-
-Shared Module Data
-------------------
-
-Objects stored in modules but not in the ZODB are not persistent and
-not-thread safe. In general it's not a good idea to store data (as
-opposed to functions, and class definitions) in modules when using
-ZODB.
-
-
-If you decide to use module data which can change you'll need to
-protect it with a lock to ensure that only one thread at a time can
-make changes.
-
-
-For example::
-
-  from threading import Lock
-  queue=[]
-  l=Lock()
-
-  def put(obj):
-      l.acquire()
-      try:
-          queue.append(obj)
-      finally:
-          l.release()
-
-  def get():
-      l.acquire()
-      try:
-          return queue.pop()
-      finally:
-          l.release()
-
-Note, in most cases where you are tempted to use shared module data,
-you can likely achieve the same result with a single persistent
-object. For example, the above queue could be replaced with a single
-instance of this class::
-
-  class Queue(Persistent):
-
-      def __init__(self):
-          self.list=[]
-
-      def put(self, obj):
-          self.list=self.list + [obj]
-
-      def get(self):
-          obj=self.list[-1]
-          self.list=self.list[0:-1]
-          return obj
-
-Notice how this class uses the mutable object 'self.list'
-immutably. If this class used 'self.list.pop' and 'self.list.append',
-then the persistence machinary would not notice that 'self.list' had
-changed.
-
-Shared External Resources
-=========================
-
-A final category of data for which you'll need to handle
-thread-safety is external resources such as files in the filesystem,
-and other processes. In practice, these concerns rarely come up.
-
-Other ZODB Resources
-====================
-
-This chapter has only covered the most important features of ZODB
-from a Zope developer's perspective. Check out some of these sources
-for more in depth information:
-
-- Andrew Kuchling's `ZODB pages <http://www.kuchling.com/zodb/>`_
-  include lots of information included a programmer's guide and links
-  to ZODB mailing lists.
-
-- `ZODB Wiki <http://wiki.zope.org/ZODB>`_ has information about
-  current ZODB projects.
-
-- `ZODB UML
-  Model <http://www.zope.org/Documentation/Developer/Models/ZODB>`_ has
-  the nitty gritty details on ZODB.
-
-- Paper `Introduction to the Zope Object Database
-  <http://www.python.org/workshops/2000-01/proceedings/papers/fulton/zodb3.html>`_
-  by Jim Fulton, presented at the 8th Python Conference.
-
-Summary
-=======
-
-The ZODB is a complex and powerful system. However using persistent
-objects is almost completely painless. Seldom do you need to concern
-yourself with thread safety, transactions, conflicts, memory
-management, and database replication. ZODB takes care of these things
-for you. By following a few simple rules you can create persistent
-objects that just work.
-

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/conf.py
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/conf.py	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/conf.py	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,190 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Zope Developer's Guide documentation build configuration file, created by
-# sphinx-quickstart on Mon Feb 16 22:23:29 2009.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# The contents of this file are pickled, so don't put values in the namespace
-# that aren't pickleable (module imports are okay, they're removed automatically).
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os
-
-# If your extensions are in another directory, add it here. If the directory
-# is relative to the documentation root, use os.path.abspath to make it
-# absolute, like shown here.
-#sys.path.append(os.path.abspath('.'))
-
-# General configuration
-# ---------------------
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = []
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The encoding of source files.
-#source_encoding = 'utf-8'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General information about the project.
-project = u"Zope Developer's Guide"
-copyright = u'2009, Zope Community'
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = '2.12'
-# The full version, including alpha/beta/rc tags.
-release = '2.12dev'
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
-
-# List of documents that shouldn't be included in the build.
-#unused_docs = []
-
-# List of directories, relative to source directory, that shouldn't be searched
-# for source files.
-exclude_trees = []
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-
-# Options for HTML output
-# -----------------------
-
-# The style sheet to use for HTML and HTML Help pages. A file of that name
-# must exist either in Sphinx' static/ path, or in one of the custom paths
-# given in html_static_path.
-html_style = 'default.css'
-
-# The name for this set of Sphinx documents.  If None, it defaults to
-# "<project> v<release> documentation".
-#html_title = None
-
-# A shorter title for the navigation bar.  Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-#html_use_modindex = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, the reST sources are included in the HTML build as _sources/<name>.
-#html_copy_source = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it.  The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = ''
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'ZopeDevelopersGuidedoc'
-
-
-# Options for LaTeX output
-# ------------------------
-
-# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
-
-# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, document class [howto/manual]).
-latex_documents = [
-  ('index', 'ZopeDevelopersGuide.tex', ur"Zope Developer's Guide",
-   ur'Zope Community', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_use_modindex = True

Deleted: zope2docs/branches/baijum-reorganize/zdgbook/source/index.rst
===================================================================
--- zope2docs/branches/baijum-reorganize/zdgbook/source/index.rst	2009-10-10 05:51:12 UTC (rev 104983)
+++ zope2docs/branches/baijum-reorganize/zdgbook/source/index.rst	2009-10-10 06:04:16 UTC (rev 104984)
@@ -1,17 +0,0 @@
-Zope Developer's Guide
-======================
-
-.. toctree::
-   :numbered:
-   :maxdepth: 2
-
-   Introduction.rst
-   GettingStarted.rst
-   ComponentsAndInterfaces.rst
-   ObjectPublishing.rst
-   Products.rst
-   ZODBPersistentComponents.rst
-   Acquisition.rst
-   Security.rst
-   TestingAndDebugging.rst
-   AppendixA.rst



More information about the checkins mailing list