<?xml version="1.0" encoding="ISO-8859-15"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#"
      xmlns:dc="http://purl.org/dc/elements/1.1/">
  <title mode="escaped" type="text/html">Florent Guillaume</title>
  <tagline>ATOM Feed - Florent Guillaume</tagline>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume" />
  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume</id>
  <generator url="http://cps-project.org" version="3">CPS</generator>
  <modified>2005-01-25 16:18:24</modified>

  <link rel="service.feed"
        href=" http://blogs.nuxeo.com/sections/blogs/florent_guillaume/atomFeed"
        title="Florent Guillaume"
        type="application/atom+xml" />
  <link rel="service.post"
        href=" http://blogs.nuxeo.com/sections/blogs/florent_guillaume/postAtom"
        title="Florent Guillaume"
        type="application/atom+xml" />
  <link rel="service.categories"
        href=" http://blogs.nuxeo.com/sections/blogs/florent_guillaume/atomCategories"
        title="Florent Guillaume"
        type="application/atom+xml" />

  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">JavaOne 2007 Slides</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2007_05_12_javaone-2007-slides" />
  <issued>2007-05-12T01:06:05Z</issued>
  <modified>2007-05-12T01:06:05Z</modified>
  <created>2007-05-12T01:00:41Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>apogee</dc:subject>
  
  
    <dc:subject>eclipse</dc:subject>
  
  
    <dc:subject>ecm</dc:subject>
  
  
    <dc:subject>java</dc:subject>
  
  
    <dc:subject>jboss</dc:subject>
  
  
    <dc:subject>nuxeo</dc:subject>
  
  
    <dc:subject>nuxeo5</dc:subject>
  
  
    <dc:subject>slides</dc:subject>
  
  
  <summary type="text/html" mode="escaped">JavaOne is now finished. We
  had a very interesting few days there, meeting lots of people interested in
  Nuxeo and wanting to know
  more about the technology and the business around it. My talk itself was
  well received, and I hope it gave people a good sense of what is possible
  and desirable in the Open Source
  ECM problem space.
   
   You can view the 
  slides of the talk ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;a href="http://java.sun.com/javaone/sf/"&gt;JavaOne&lt;/a&gt; is now finished. We
  had a very interesting few days there, meeting lots of people interested in
  &lt;a href="http://www.nuxeo.com/en/products/"&gt;Nuxeo&lt;/a&gt; and wanting to know
  more about the technology and the business around it. My talk itself was
  well received, and I hope it gave people a good sense of what is possible
  and desirable in the &lt;a href="http://www.nuxeo.com/en/ecm/"&gt;Open Source
  ECM&lt;/a&gt; problem space.&lt;br /&gt;
   &lt;br /&gt;
   You can view the &lt;a
  href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2007_05_12_javaone-2007-slides/downloadFile/attachedFile_f0/Nuxeo-JavaOne-2007.pdf"&gt;
  slides of the talk here&lt;/a&gt;.&lt;br /&gt;
   &lt;br /&gt;
   I also attended some very interesting sessions regarding subjects that are
  important when writing an ECM framework: persistence, distribution,
  scalability, validation, object-relational modeling, etc. A number of
  efforts are ongoing to standardize as JSRs some important aspects related to
  this. In the coming days I'll be blogging in more detail about these JSRs
  that we'll be tracking closely.&lt;br /&gt;
   &lt;br /&gt;
   For our first participation, this was a very fruitful experience, and we'll
  certainly be going again next year!&lt;br /&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2007_05_12_javaone-2007-slides</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2007_05_12_javaone-2007-slides/atom?2007_05_12_javaone-2007-slides"
        title="Edit Here - JavaOne 2007 Slides" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Discover Nuxeo 5 at JavaOne 2007</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2007_05_03_discover-nuxeo-5-at-javaone-2007" />
  <issued>2007-05-03T16:19:03Z</issued>
  <modified>2007-05-03T16:19:03Z</modified>
  <created>2007-05-03T16:19:02Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>apogee</dc:subject>
  
  
    <dc:subject>eclipse</dc:subject>
  
  
    <dc:subject>ecm</dc:subject>
  
  
    <dc:subject>java</dc:subject>
  
  
    <dc:subject>jboss</dc:subject>
  
  
    <dc:subject>nuxeo</dc:subject>
  
  
    <dc:subject>nuxeo5</dc:subject>
  
  
    <dc:subject>slides</dc:subject>
  
  
  <summary type="text/html" mode="escaped">JavaOne 2007 is in a few days
  now, and we'll be giving a talk about Nuxeo 5.
   
   The talk has ID 
  TS-4532 (in the Java EE track), and takes place on Thursday the 10th at
  5:30 pm in Hall E - 134. The title of the session is 
  Building an Embeddable Enterprise Content Management Core with the Latest
  Java Technologies. 
   
   This is a great opportunity if you want to discover ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;a href="http://java.sun.com/javaone/sf/"&gt;JavaOne 2007&lt;/a&gt; is in a few days
  now, and we'll be giving a talk about &lt;a
  href="http://www.nuxeo.com/en/products/"&gt;Nuxeo 5&lt;/a&gt;.&lt;br /&gt;
   &lt;br /&gt;
   The talk has ID &lt;a
  href="http://www28.cplan.com/cc158/sessions_catalog.jsp?is=yes&amp;amp;icriteria9=TS-4532"&gt;
  TS-4532&lt;/a&gt; (in the Java EE track), and takes place on Thursday the 10th at
  5:30 pm in Hall E - 134. The title of the session is &lt;a
  href="http://www28.cplan.com/cc158/session_details.jsp?isid=286532&amp;amp;ilocation_id=158-1&amp;amp;ilanguage=english"&gt;
  Building an Embeddable Enterprise Content Management Core with the Latest
  Java Technologies&lt;/a&gt;. &lt;br /&gt;
   &lt;br /&gt;
   This is a great opportunity if you want to discover more about how Nuxeo 5
  is architected, see demos of the product, or talk to us about technical or
  business-related questions.&lt;br /&gt;
   &lt;br /&gt;
   As a teaser, here's the overview of the talk:&lt;br /&gt;
   &lt;br /&gt;
   &lt;b&gt;Learn about the design and use of Nuxeo 5, an embeddable, extensible
  Enterprise Content Management framework for Java EE and other
  platforms&lt;/b&gt;&lt;br /&gt;
   &lt;br /&gt;
   Agenda:&lt;br /&gt;
   

  &lt;ul&gt;
   &lt;li&gt;What is Enterprise Content Management&lt;/li&gt;

   &lt;li&gt;What do we want to achieve&lt;/li&gt;

   &lt;li&gt;Core Framework&lt;/li&gt;

   &lt;li&gt;Core and High-Level Services&lt;/li&gt;

   &lt;li&gt;UI Layers&lt;/li&gt;

   &lt;li&gt;Extensible and Pluggable&lt;/li&gt;

   &lt;li&gt;Using the Framework&lt;/li&gt;
  &lt;/ul&gt;
  &lt;br /&gt;
   See you in San Francisco!&lt;br /&gt;
  &lt;br /&gt;
   &lt;br /&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2007_05_03_discover-nuxeo-5-at-javaone-2007</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2007_05_03_discover-nuxeo-5-at-javaone-2007/atom?2007_05_03_discover-nuxeo-5-at-javaone-2007"
        title="Edit Here - Discover Nuxeo 5 at JavaOne 2007" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">What's the point of JCR?</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2006_10_18_what-s-point-jcr" />
  <issued>2006-10-18T15:39:45Z</issued>
  <modified>2006-10-18T15:39:45Z</modified>
  <created>2006-10-18T15:33:08Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>cps</dc:subject>
  
  
    <dc:subject>ecm</dc:subject>
  
  
    <dc:subject>java</dc:subject>
  
  
    <dc:subject>nuxeo5</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
Nuxeo is switching its ECM to Java, and we're using JCR for our document storage. JCR (Java Content Repository, standardized by JSR-170 and the upcoming JSR-283) is a young specification with a promising future &amp;mdash; but what's its point, you may ask, as all existing content management systems are already storing content very well without it? Its goal is interoperability between vendors, ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;
Nuxeo is switching its &lt;a href="http://www.nuxeo.com/en/products/"&gt;ECM&lt;/a&gt; to Java, and we're using &lt;a href="http://jcp.org/en/jsr/detail?id=170"&gt;JCR&lt;/a&gt; for our document storage. JCR (Java Content Repository, standardized by &lt;a href="http://jcp.org/en/jsr/detail?id=170"&gt;JSR-170&lt;/a&gt; and the upcoming &lt;a href="http://jcp.org/en/jsr/detail?id=283"&gt;JSR-283&lt;/a&gt;) is a young specification with a promising future &amp;mdash; but what's its point, you may ask, as all existing content management systems are already storing content very well without it? Its goal is &lt;em&gt;interoperability&lt;/em&gt; between vendors, which will make it possible for people who write applications needing to store content to have a unified API for such manipulations. All major content repository vendors are active in the JSR-283 expert group, and all are working on JCR bindings for their various proprietary repositories.
&lt;/p&gt;
&lt;p&gt;
Of course a standardized and wildly successful way of manipulating content already existed before JCR: &lt;a href="http://en.wikipedia.org/wiki/SQL"&gt;SQL&lt;/a&gt;. But SQL and JCR have a different focus:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQL is a language; it manipulates rows and is geared toward generic relation manipulation,&lt;/li&gt;
&lt;li&gt;JCR is a Java API; it manipulates nodes and is geared toward hierarchical manipulation (parent-children).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
SQL and JCR have quite different underlying data models:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQL's model is that of tables with fixed schemas, and relations between tables,&lt;/li&gt;
&lt;li&gt;JCR's model is that of a tree of nodes with flexible schemas and with parent-children relations as the main focus &amp;mdash; although other types of relations exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
JCR also offers higher level features than SQL, notably workspace and version management.
&lt;/p&gt;
&lt;p&gt;
For many kinds of applications, there is a focus on being able to arrange documents in folder hierarchies, and to have a wild variety of structure for these documents. In this case, a storage model based on JCR is much more suited than something based on SQL.
&lt;/p&gt;
&lt;p&gt;
It should be noted that many things in the computing world already are based on the notion of folder hierarchies storing arbitrary documents:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;filesystems are a tree of (unstructured) documents,&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Revision_control"&gt;Revision control systems&lt;/a&gt; are based on filesystem concepts but add a lot of structure on top of them,&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.webdav.org/"&gt;WebDAV&lt;/a&gt; (along with DAV and DELTAV) is a protocol that addresses documents using a path, and where documents have a flexible set of properties,&lt;/li&gt;
&lt;li&gt;most proprietary content management systems are based on (or offer the notion of) organizing the content in a hierarchy,&lt;/li&gt;
&lt;li&gt;Nuxeo's &lt;a href="http://www.nuxeo.com/en/products/cps/"&gt;CPS&lt;/a&gt; is itself based on this classic model.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
This is why JCR has emerged as a common and useful storage API for all these use cases.
&lt;/p&gt;
&lt;p&gt;
For an ECM framework like &lt;a href="http://www.nuxeo.com/en/products/ "&gt;Nuxeo 5&lt;/a&gt;, JCR interoperability can be seen from two different directions:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JCR provides an API that we can use to store our content, to make us vendor-independent and flexible regarding storage,&lt;/li&gt;
&lt;li&gt;JCR provides an API through which we can expose our content, which makes our platform usable by any external system that understands it &amp;mdash; we're ourselves a vendor providing JCR bindings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
For its initial release, Nuxeo 5 is focusing on the use of JCR as its main storage implementation and uses &lt;a href="http://jackrabbit.apache.org/"&gt;Jackrabbit&lt;/a&gt; to store most of our content. In the future, we'll also provide JCR bindings so that the high-level content we provide can be directly accessed from external applications using JCR too.
&lt;/p&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2006_10_18_what-s-point-jcr</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2006_10_18_what-s-point-jcr/atom?2006_10_18_what-s-point-jcr"
        title="Edit Here - What's the point of JCR?" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Nuxeo 5: Unifying the content APIs</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2006_10_18_nuxeo-5-unifying-content-apis" />
  <issued>2006-10-18T10:53:47Z</issued>
  <modified>2006-10-18T10:53:47Z</modified>
  <created>2006-10-18T10:53:46Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>cps</dc:subject>
  
  
    <dc:subject>ecm</dc:subject>
  
  
    <dc:subject>java</dc:subject>
  
  
    <dc:subject>nuxeo5</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
In a content management system, the actual data that the system or the users manipulate comes from many kinds of sources. Content can come from a JCR repository, or from a relational database, or from an LDAP directory, or from a semantic storage engine like Jena, or from any other kind of open or proprietary storage engine.


But fundamentally all these kinds of content, which I'll call ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;
In a content management system, the actual data that the system or the users manipulate comes from many kinds of sources. Content can come from a &lt;a href="http://jcp.org/en/jsr/detail?id=170"&gt;JCR&lt;/a&gt; repository, or from a &lt;a href="http://en.wikipedia.org/wiki/Relational_database"&gt;relational database&lt;/a&gt;, or from an &lt;a href="http://en.wikipedia.org/wiki/LDAP"&gt;LDAP&lt;/a&gt; directory, or from a semantic storage engine like &lt;a href="http://jena.sourceforge.net/"&gt;Jena&lt;/a&gt;, or from any other kind of open or proprietary storage engine.
&lt;/p&gt;
&lt;p&gt;
But fundamentally all these kinds of content, which I'll call "records", aren't very different:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a record can be created, viewed, modified, deleted,&lt;/li&gt;
&lt;li&gt;a record can often be copied or moved,&lt;/li&gt;
&lt;li&gt;a record obeys a schema that can be known to the system, this means that its individual fields are strictly typed,&lt;/li&gt;
&lt;li&gt;when being viewed or modified, a record has a user interface that is based on forms, labels, widgets, depending on the schema,&lt;/li&gt;
&lt;li&gt;records can be searched and a result set returned,&lt;/li&gt;
&lt;li&gt;records can be listed in a compact form (search results, folder contents, user dashboard, workflow workitems, RDB table listing, user information browsing, etc.),&lt;/li&gt;
&lt;li&gt;records have an identity (like a unique id) or a location (like a path), sometimes both.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
One of the strengths of &lt;a href="http://www.nuxeo.com/en/products/cps/"&gt;CPS&lt;/a&gt; is to use a common abstraction for many of these concepts, embodied in the CPSSchemas component. In &lt;a href="http://www.nuxeo.com/en/products/"&gt;Nuxeo 5&lt;/a&gt; we want to go further and provide even more integration for all these, the base components for these abstractions are &lt;a href="http://maven.nuxeo.org/NXCore/"&gt;NXCore&lt;/a&gt; and &lt;a href="http://maven.nuxeo.org/NXTypeManager/"&gt;NXTypeManager&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
The reasons to strive for convergence are numerous:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;this merges into unique concepts things that had been previously separated because of different implementation choices. For instance, an LDAP schema is not fundamentally different from an SQL schema (or from an &lt;a href="http://www.w3.org/XML/Schema"&gt;XML Schema&lt;/a&gt; if one is interested in the relevant subset).&lt;/li&gt;
&lt;li&gt;this gives the programmers a common API for all data-related operations, which means more reusability. For instance changing an attribute in an LDAP entry doesn't have to be different from changing the title of a document or changing a value in an RDB row; processing a list of search results to display them in a table doesn't have to be different from processing the children of a folder to display the folder's contents.&lt;/li&gt;
&lt;li&gt;this gives the framework developers a way to optimize some operations because of commonalities in the underlying implementations. For instance you don't need three kinds of events dispatching for "LDAP entry modified", "RDB row modified" or "document modified".&lt;/li&gt;
&lt;li&gt;this gives the users a unified way of manipulating different kinds of data when there's really no need to have a different UI for them. When a user fills a form it's really the same process whether he's modifying his personal preferences, adding a keyword to a document, or changing a quantity in an RDB row.&lt;/li&gt;
&lt;li&gt;this allows very simple migrations between storage technologies, when these are felt necessary. A customer could start with an LDAP database for its user base and later have the need to move them to an RDB table. User entries in an RDB table may need to be versioned and moved to a JCR storage. An application should survive all these with only configuration changes and no code to rewrite.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
It should be noted that this means that JCR is in no way the primary storage model for Nuxeo 5, it's only the first one to be implemented. In the future, it will be possible to store documents in LDAP or an RDB. When a suitable storage model is devised and implemented, you'll be able to apply workflow or versioning to RDB-based documents for instance.
&lt;/p&gt;
&lt;p&gt;
This convergence is quite exciting to us, and our goal is to allow people to build complex applications with Nuxeo 5 in a more straightforward manner.
&lt;/p&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2006_10_18_nuxeo-5-unifying-content-apis</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2006_10_18_nuxeo-5-unifying-content-apis/atom?2006_10_18_nuxeo-5-unifying-content-apis"
        title="Edit Here - Nuxeo 5: Unifying the content APIs" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">GenericSetup for CPS, CMF and Zope</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2006_01_24_genericsetup-for-cps-cmf" />
  <issued>2006-11-05T18:28:59Z</issued>
  <modified>2006-11-05T18:28:59Z</modified>
  <created>2006-01-24T19:02:56Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>cps</dc:subject>
  
  
    <dc:subject>five</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
    <dc:subject>zope3</dc:subject>
  
  
  <summary type="text/html" mode="escaped">GenericSetup is a framework to describe the configuration of a Zope site
as a set of XML files (and sometimes other associated files). It can
import profiles, which may create objects or change their configuration,
and export profiles, which makes a snapshot of the configuration and
writes it to a set of XML files.
GenericSetup provides a tool that can store snapshots of a configuration
in ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;GenericSetup is a framework to describe the configuration of a Zope site
as a set of XML files (and sometimes other associated files). It can
import profiles, which may create objects or change their configuration,
and export profiles, which makes a snapshot of the configuration and
writes it to a set of XML files.&lt;/p&gt;
&lt;p&gt;GenericSetup provides a tool that can store snapshots of a configuration
in the ZODB itself, where it can be examined and even modified. It can
also do diffs between two snapshots, which is very useful to find out
what changed in a configuration (it's a good idea to take a full
snapshot anytime some significant changes are made to the
configuration).&lt;/p&gt;
&lt;p&gt;GenericSetup differentiates between Base and Extension profiles. A Base
profile is a profile that describes &amp;quot;everything&amp;quot;. When it is imported,
it removes and overwrites any previous configuration. An Extension
profile is a profile designed to be incrementally added on top of a
previously existing configuration. It may of course overwrite some
settings, or even in some case remove objects, but its goal is generally
to add optional configuration on top of a main one&lt;/p&gt;
&lt;p&gt;GenericSetup is based on a small number of concepts: the toolset, and
some import and export steps. GenericSetup provides a framework where
import and export steps can be written simply using Zope 3 adapters.&lt;/p&gt;
&lt;p&gt;GenericSetup was born as &amp;quot;CMFSetup&amp;quot; but was later made generic and can
be used by any Zope 2 application. It is now available at
&lt;a class="reference" href="http://svn.zope.org/GenericSetup/trunk/"&gt;http://svn.zope.org/GenericSetup/trunk/&lt;/a&gt;. A subclass with additional
features is used in &lt;a class="reference" href="http://www.cps-project.org/"&gt;CPS&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="setup-tool"&gt;
&lt;h1&gt;&lt;a name="setup-tool"&gt;Setup tool&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The setup tool is called &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;setup_tool&lt;/span&gt;&lt;/tt&gt; by default, and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;portal_setup&lt;/span&gt;&lt;/tt&gt;
in CPS (if missing, it can be instantiated by selecting &amp;quot;CPS Tools&amp;quot; from
the ZMI Add menu).&lt;/p&gt;
&lt;p&gt;At a given time, the setup tool knows about a few things:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;the currently selected profile, which may point to an area in the
filesystem where a profile has been registered, or to a path in the
ZODB where a snapshot was taken,&lt;/li&gt;
&lt;li&gt;the current toolset,&lt;/li&gt;
&lt;li&gt;the current import steps,&lt;/li&gt;
&lt;li&gt;the current export steps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a new profile it selected, its toolset, import steps and export
steps XML files are loaded and merged with the tool's current ones.&lt;/p&gt;
&lt;p&gt;Any import or export is based on the &lt;em&gt;full&lt;/em&gt; toolset or import/export
steps (even if the currently selected profile is an extension profile),
but the source of XML configuration files depends solely on the
currently selected profile.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="toolset"&gt;
&lt;h1&gt;&lt;a name="toolset"&gt;Toolset&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The file &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;toolset.xml&lt;/span&gt;&lt;/tt&gt; describes the Toolset, which is the set of
tools needed in a given configuration. (While the name &amp;quot;tool&amp;quot; would
suggest CMF, it's just a set of objects that can be instantiated at the
root of the configured site.)&lt;/p&gt;
&lt;p&gt;Beyond being based on data that is updated when an extension profile is
selected, the toolset is a normal import/export step.&lt;/p&gt;
&lt;p&gt;When the toolset is imported, all the objects in the toolset are
instantiated if they're missing or if their class doesn't match with
what it's supposed to be.&lt;/p&gt;
&lt;p&gt;An excerpt of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;toolset.xml&lt;/span&gt;&lt;/tt&gt; for the CPS Tree Tool would be:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;
&amp;lt;tool-setup&amp;gt;
  ...
  &amp;lt;required tool_id=&amp;quot;portal_trees&amp;quot;
            class=&amp;quot;Products.CPSCore.TreeTool.TreeTool&amp;quot;/&amp;gt;
  ...
&amp;lt;/tool-setup&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="import-steps"&gt;
&lt;h1&gt;&lt;a name="import-steps"&gt;Import steps&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Import steps (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;import_steps.xml&lt;/span&gt;&lt;/tt&gt;) describe a set of configuration
steps available for import, and their dependencies. A step is just the
dotted name of a function, and the dependencies is simply the steps that
have to be run before this one can be done (most steps depend on the
toolset, because they need a base tool to be instantiated before it can
be configured).&lt;/p&gt;
&lt;p&gt;While an import step can do anything it likes, GenericSetup provides a
framework based on Zope 3 adapters to simply describe how a single
object is imported from XML, and to recurse among objects to create or
configure them one by one.&lt;/p&gt;
&lt;div class="section" id="purge"&gt;
&lt;h2&gt;&lt;a name="purge"&gt;Purge&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;During import, there are two possible behaviors, corresponding to the
two kinds of profiles. For a Base profile, the import happens in &amp;quot;purge&amp;quot;
mode, while for an extension profile the import doesn't purge. The
functions and adapters doing the import have to take that into account
when they read a profile.&lt;/p&gt;
&lt;p&gt;In purge mode, every previous configuration has to be removed, so that
the result is indistinguishable from an install from scratch. In
non-purge mode, care must be taken to not overwrite or remove settings
or objects which are not explicitely specified in the imported XML file.&lt;/p&gt;
&lt;p&gt;An excerpt of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;import_steps.xml&lt;/span&gt;&lt;/tt&gt; for the CPS Tree Tool would be:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;
&amp;lt;import-steps&amp;gt;
  ...
  &amp;lt;import-step id=&amp;quot;trees&amp;quot; version=&amp;quot;20051230-01&amp;quot;
               handler=&amp;quot;Products.CPSCore.exportimport.importTreeTool&amp;quot;
               title=&amp;quot;Tree Tool&amp;quot;&amp;gt;
    &amp;lt;dependency step=&amp;quot;toolset&amp;quot;/&amp;gt;
    Import tree tool and tree caches.
  &amp;lt;/import-step&amp;gt;
  ...
&amp;lt;/import-steps&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="export-steps"&gt;
&lt;h1&gt;&lt;a name="export-steps"&gt;Export steps&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Export steps (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;export_steps.xml&lt;/span&gt;&lt;/tt&gt;) describe the list of steps available
for export. An export step is used in exactly the same way than an
import step, except for the fact that there are no dependencies between
export steps, and that instead of being read, XML files are written.&lt;/p&gt;
&lt;p&gt;One important thing to note is that export steps &lt;em&gt;cannot&lt;/em&gt; do the
&amp;quot;incremental exports&amp;quot; that many people expect. When an extension profile
is read by the import steps, only the available XML files for that
profile are read. However when writing, there's no way to choose which
XML files are relevant, so the whole profile for that step is written
(and recursion is done in all subobjects).&lt;/p&gt;
&lt;p&gt;It's possible that future versions of GenericSetup will have some
capabilities to do incremental exports, but this is not possible for
now.&lt;/p&gt;
&lt;p&gt;An excerpt of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;export_steps.xml&lt;/span&gt;&lt;/tt&gt; for the CPS Tree Tool would be:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;
&amp;lt;export-steps&amp;gt;
  ...
  &amp;lt;export-step id=&amp;quot;trees&amp;quot;
               handler=&amp;quot;Products.CPSCore.exportimport.exportTreeTool&amp;quot;
               title=&amp;quot;Tree Tool&amp;quot;&amp;gt;
    Export tree tool and tree caches.
  &amp;lt;/export-step&amp;gt;
  ...
&amp;lt;/export-steps&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="adapters"&gt;
&lt;h1&gt;&lt;a name="adapters"&gt;Adapters&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The standard work done in an import or export step is to find the base
tool, and call &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;importObjects&lt;/span&gt;&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;exportObjects&lt;/span&gt;&lt;/tt&gt; on it; these are
recursive functions that take each object, find an adapter for them
describing how the XML import or export is done, and call it.&lt;/p&gt;
&lt;p&gt;For the CPS Tree Tool, the import steps and export steps call the
following functions:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
def exportTreeTool(context):
    &amp;quot;&amp;quot;&amp;quot;Export Tree tool and tree caches as a set of XML files.
    &amp;quot;&amp;quot;&amp;quot;
    site = context.getSite()
    tool = getToolByName(site, 'portal_trees', None)
    if tool is None:
        logger = context.getLogger('trees')
        logger.info(&amp;quot;Nothing to export.&amp;quot;)
        return
    exportObjects(tool, '', context)

def importTreeTool(context):
    &amp;quot;&amp;quot;&amp;quot;Import Tree tool and tree caches as a set of XML files.
    &amp;quot;&amp;quot;&amp;quot;
    site = context.getSite()
    tool = getToolByName(site, 'portal_trees')
    importObjects(tool, '', context)
&lt;/pre&gt;
&lt;p&gt;This is pretty boileplate and could even be simplified in the future
through ZCML declarations. Above, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;''&lt;/span&gt;&lt;/tt&gt; simply refers to the root of
the profile directory.&lt;/p&gt;
&lt;p&gt;The adapters are multi-adapters, adapting both an object and an import
context (called &amp;quot;environ&amp;quot; in GenericSetup), to the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;IBody&lt;/span&gt;&lt;/tt&gt; interface
that basically describes a file body. They can be registered through
ZCML using the standard statement:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;adapter
    factory=&amp;quot;.exportimport.TreeToolXMLAdapter&amp;quot;
    provides=&amp;quot;Products.GenericSetup.interfaces.IBody&amp;quot;
    for=&amp;quot;.interfaces.ITreeTool
         Products.GenericSetup.interfaces.ISetupEnviron&amp;quot;
    /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This assumes of course that the exported object is described through an
interface, for instance here declared as:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
from zope.interface import Interface

class ITreeTool(Interface):
    &amp;quot;&amp;quot;&amp;quot;Tree Tool.
    &amp;quot;&amp;quot;&amp;quot;
&lt;/pre&gt;
&lt;p&gt;The interface is implemented by the object's class with:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
from zope.interface import implements

class TreeTool(UniqueObject, Folder):
    &amp;quot;&amp;quot;&amp;quot;Tree Tool that caches information about the site's hierarchies.
    &amp;quot;&amp;quot;&amp;quot;
    implements(ITreeTool)

    id = 'portal_trees'
    meta_type = 'CPS Tree Tool'
    ...
&lt;/pre&gt;
&lt;p&gt;When doing an export, the adapters build a DOM tree for the
configuration. When doing an import, they read the DOM tree and create
or modify properties as needed. The standard adapters don't create
subobjects or recurse in them, this is left to the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;importObjects&lt;/span&gt;&lt;/tt&gt;
function.&lt;/p&gt;
&lt;p&gt;These adapters can be written easily because GenericSetup provides
helpers for the common cases of objects configured only through standard
Zope 2 properties (PropertyManager), or having subobjects
(ObjectManager).&lt;/p&gt;
&lt;p&gt;Of course all this can be changed for specific cases. Many older CMF
tools are configured through things that are not standard properties,
and for instance CPS needs to do recursion into more than simple
ObjectManager subobjects. It is also possible to read and write files
that are not XML files, CPS does this for the images included in portlet
objects, where it writes a real image file.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="additional-cps-feature-upgrades"&gt;
&lt;h1&gt;&lt;a name="additional-cps-feature-upgrades"&gt;Additional CPS feature: upgrades&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;CPS has extended the setup tool to provide a basic Upgrade feature, that
is related to the configuration of the site but cannot be expressed by
the standard GenericSetup profiles.&lt;/p&gt;
&lt;p&gt;An upgrade step is registered through ZCML with something like:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;cps:upgradeStep
    title=&amp;quot;Replace CMF URL tool with a CPS-specific one&amp;quot;
    source=&amp;quot;3.3.4&amp;quot; destination=&amp;quot;3.3.5&amp;quot;
    handler=&amp;quot;.upgrade.upgradeURLTool&amp;quot;
    checker=&amp;quot;.upgrade.check_upgradeURLTool&amp;quot;
    /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This describes between what CPS versions this upgrade is needed, how to
do it, and how to check if it's already been done.&lt;/p&gt;
&lt;p&gt;The setup tool lists which steps have not yet been done, and provides a
way to run them one by one or all at once. At a given time, a CPS site
&amp;quot;knows&amp;quot; (through a site-global property &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;last_upgraded_version&lt;/span&gt;&lt;/tt&gt;) up to
which version it's been upgraded.&lt;/p&gt;
&lt;p&gt;The checker is optional; if it would be too costly to check for the
conversion, it can be omitted. This is the case typically for an upgrade
step that would recurse in the content object to do some fixups; to
check if they've already been done it would have to recurse in the
content objects too, and that's too much work for a simple check. The
setup tool won't list a step without a checker if the portal has already
been upgraded to a later version than the step's &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;destination&lt;/span&gt;&lt;/tt&gt;
version.&lt;/p&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2006_01_24_genericsetup-for-cps-cmf</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2006_01_24_genericsetup-for-cps-cmf/atom?2006_01_24_genericsetup-for-cps-cmf"
        title="Edit Here - GenericSetup for CPS, CMF and Zope" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Object event dispatching in Zope</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_11_10_object-event-dispatching" />
  <issued>2005-11-10T00:35:01Z</issued>
  <modified>2005-11-10T00:35:01Z</modified>
  <created>2005-11-10T00:34:43Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>zope</dc:subject>
  
  
    <dc:subject>zope3</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Here are some explanations about what happens in Zope 3.2 (and Zope 2.9
when using Five) when an event notification is sent by some code, up to
a specific subscriber. It focuses more specifically on object events,
which go through some additional hoops. All this is complex because
there are many simple components that are linked together.
Let's start with some framework code that sends an ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;Here are some explanations about what happens in Zope 3.2 (and Zope 2.9
when using Five) when an event notification is sent by some code, up to
a specific subscriber. It focuses more specifically on object events,
which go through some additional hoops. All this is complex because
there are many simple components that are linked together.&lt;/p&gt;
&lt;p&gt;Let's start with some framework code that sends an event after an object
has been added (similar to what &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;zope.app.container.contained&lt;/span&gt;&lt;/tt&gt;
actually does):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
event = ObjectAddedEvent(ob, container, name)
zope.event.notify(event)
&lt;/pre&gt;
&lt;p&gt;In &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;zope.event&lt;/span&gt;&lt;/tt&gt; we have the definition for this function:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
subscribers = [] # registered subscribers
def notify(event):
    for subscriber in subscribers:
        subscriber(event)
&lt;/pre&gt;
&lt;p&gt;During initialization, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;zope.app.event.dispatching&lt;/span&gt;&lt;/tt&gt; has registered a
subscriber:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
def dispatch(*event):
    # Iterating over subscribers assures they get executed.
    for ignored in zope.component.subscribers(event, None):
        pass
zope.event.subscribers.append(dispatch)
&lt;/pre&gt;
&lt;p&gt;The function &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;zope.component.subscribers&lt;/span&gt;&lt;/tt&gt; will then call all matching
subscribers.&lt;/p&gt;
&lt;p&gt;During initialization, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;zope/app/event/configure.zcml&lt;/span&gt;&lt;/tt&gt; has registered
a subscriber for &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;zope.app.event.interfaces.IObjectEvent&lt;/span&gt;&lt;/tt&gt; with the
handler &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;zope.app.event.objectevent.objectEventNotify&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;subscriber
    for=&amp;quot;zope.app.event.interfaces.IObjectEvent&amp;quot;
    handler=&amp;quot;zope.app.event.objectevent.objectEventNotify&amp;quot;
    /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This handler does:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
def objectEventNotify(event):
    adapters = zope.component.subscribers((event.object, event), None)
    for adapter in adapters:
        pass # Getting them does the work.
&lt;/pre&gt;
&lt;p&gt;This means that the event will be redispatched, but this time a
subscriber can match using multi-adaptation on both the object and the
event interfaces, which gives much more flexibility and filtering
possibilities.&lt;/p&gt;
&lt;p&gt;During initialization, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;zope/app/container/configure.zcml&lt;/span&gt;&lt;/tt&gt; has
registered a multi-subscriber:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;subscriber
    for=&amp;quot;zope.app.location.interfaces.ILocation
         zope.app.container.interfaces.IObjectMovedEvent&amp;quot;
    handler=&amp;quot;zope.app.container.contained.dispatchToSublocations&amp;quot;
    /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Note that &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;IContained&lt;/span&gt;&lt;/tt&gt;, a base interface for most content objects,
derives from &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ILocation&lt;/span&gt;&lt;/tt&gt;, so this subscriber will match most content
objects. Also, the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;IObjectAddedEvent&lt;/span&gt;&lt;/tt&gt; sent initially derives from
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;IObjectMovedEvent&lt;/span&gt;&lt;/tt&gt; so it will be matched.&lt;/p&gt;
&lt;p&gt;When using Five, in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Five/event.zcml&lt;/span&gt;&lt;/tt&gt; some similar subscribers are
registered to react on &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;IObjectManager&lt;/span&gt;&lt;/tt&gt; instead of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ILocation&lt;/span&gt;&lt;/tt&gt;, and
to dispatch using the same handler.&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;dispatchToSublocations&lt;/span&gt;&lt;/tt&gt; handler is:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
def dispatchToSublocations(object, event):
    subs = ISublocations(object, None)
    if subs is not None:
        for sub in subs.sublocations():
            for ignored in zapi.subscribers((sub, event), None):
                pass # They do work in the adapter fetch
&lt;/pre&gt;
&lt;p&gt;This redispatches the same event to all subobjects, where &amp;quot;subobjects&amp;quot;
is defined using the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ISublocations&lt;/span&gt;&lt;/tt&gt; adapter. Now,
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;zope/app/container/configure.zcml&lt;/span&gt;&lt;/tt&gt; has an adapter:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;adapter
    for=&amp;quot;zope.app.container.interfaces.IReadContainer&amp;quot;
    provides=&amp;quot;zope.app.location.interfaces.ISublocations&amp;quot;
    factory=&amp;quot;zope.app.container.contained.ContainerSublocations&amp;quot;
    /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Most Zope 3 container objects are also &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;IReadContainer&lt;/span&gt;&lt;/tt&gt;. The
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ContainerSublocations&lt;/span&gt;&lt;/tt&gt; handler does simply get the sublocations
using:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
class ContainerSublocations(object):
    def __init__(self, container):
        self.container = container
    def sublocations(self):
        container = self.container
        for key in container:
            yield container[key]
&lt;/pre&gt;
&lt;p&gt;When using Five, a similar adapter is registered:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;adapter
    for=&amp;quot;OFS.interfaces.IObjectManager&amp;quot;
    provides=&amp;quot;zope.app.location.interfaces.ISublocations&amp;quot;
    factory=&amp;quot;OFS.subscribers.ObjectManagerSublocations&amp;quot;
    /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;And the Five adapter does something comparable to the Zope 3 one:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
class ObjectManagerSublocations(object):
    def __init__(self, container):
        self.container = container
    def sublocations(self):
        for ob in self.container.objectValues():
            yield ob
&lt;/pre&gt;
&lt;p&gt;All in all, our initial event will be redispatched to the sublocations
of the original object, and the process will be done recursively to all
the sublocations.&lt;/p&gt;
&lt;p&gt;Now some user code's &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;configure.zcml&lt;/span&gt;&lt;/tt&gt; can registered a
multi-subscriber:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;subscriber
    for=&amp;quot;.interfaces.IFoo
         zope.app.container.interfaces.IObjectAddedEvent&amp;quot;
    handler=&amp;quot;.foo.reactOnAdd&amp;quot;
    /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Which ties to the handler:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
def reactOnAdd(ob, event):
    &amp;quot;&amp;quot;&amp;quot;Does something.&amp;quot;&amp;quot;&amp;quot;
&lt;/pre&gt;
&lt;p&gt;In the handler, which will be called for all sublocations, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ob&lt;/span&gt;&lt;/tt&gt; is any
sublocation of the original object (including the object itself), and
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;event&lt;/span&gt;&lt;/tt&gt; is the original event (which means that &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;event.object&lt;/span&gt;&lt;/tt&gt; is
the original object).&lt;/p&gt;
&lt;p&gt;This concludes our dive into through Zope 3 events. You can read in
&lt;a class="reference" href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_11_08_events-in-zope-2-9"&gt;http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_11_08_events-in-zope-2-9&lt;/a&gt;
how object events can be used in Zope 2.9 to do what used to be done
using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterAdd&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_11_10_object-event-dispatching</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_11_10_object-event-dispatching/atom?2005_11_10_object-event-dispatching"
        title="Edit Here - Object event dispatching in Zope" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Events in Zope 2.9</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_11_08_events-in-zope-2-9" />
  <issued>2005-11-08T01:00:52Z</issued>
  <modified>2005-11-08T01:00:52Z</modified>
  <created>2005-11-08T00:50:21Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>zope</dc:subject>
  
  
    <dc:subject>zope3</dc:subject>
  
  
  <summary type="text/html" mode="escaped">Zope 2.9 (and Zope 2.8 when using Five 1.2) introduces a big change: Zope 3 style container events.
With container events, you finally have the ability to react to things
happening to objects without have to subclass manage_afterAdd,
manage_beforeDelete or manage_afterClone. Instead, you just have
to register a subscriber for the appropriate event, for instance
IObjectAddedEvent, and make it ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;Zope 2.9 (and Zope 2.8 when using Five 1.2) introduces a big change: Zope 3 style container events.&lt;/p&gt;
&lt;p&gt;With container events, you finally have the ability to react to things
happening to objects without have to subclass &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterAdd&lt;/span&gt;&lt;/tt&gt;,
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_beforeDelete&lt;/span&gt;&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterClone&lt;/span&gt;&lt;/tt&gt;. Instead, you just have
to register a subscriber for the appropriate event, for instance
IObjectAddedEvent, and make it do the work.&lt;/p&gt;
&lt;p&gt;Indeed, the old methods like &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterAdd&lt;/span&gt;&lt;/tt&gt; are now deprecated, you
shouldn't use them anymore.&lt;/p&gt;
&lt;p&gt;Let's see how to migrate your products.&lt;/p&gt;
&lt;div class="section" id="old-product"&gt;
&lt;h1&gt;&lt;a name="old-product"&gt;Old product&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Suppose that in an old product you have code that needs to register
through a central tool whenever a document is created. Or it could be
indexing itself. Or it could initialize an attribute according to its
current path. Code like:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
class CoolDocument(...):
    ...
    def manage_afterAdd(self, item, container):
        self.mangled_path = mangle('/'.join(self.getPhysicalPath()))
        getToolByName(self, 'portal_cool').registerCool(self)
        super(CoolDocument, self).manage_afterAdd(item, container)

    def manage_afterClone(self, item):
        self.mangled_path = mangle('/'.join(self.getPhysicalPath()))
        getToolByName(self, 'portal_cool').registerCool(self)
        super(CoolDocument, self).manage_afterClone(item)

    def manage_beforeDelete(self, item, container):
        super(CoolDocument, self).manage_beforeDelete(item, container)
        getToolByName(self, 'portal_cool').unregisterCool(self)
&lt;/pre&gt;
&lt;p&gt;This would be the best practice in Zope 2.8. Note the use of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;super()&lt;/span&gt;&lt;/tt&gt;
to call the base class, which is often omitted because people &amp;quot;know&amp;quot;
that SimpleItem for instance doesn't do anything in these methods.&lt;/p&gt;
&lt;p&gt;If you run this code in Zope 2.9, you will get deprecation warnings,
telling you that:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
Calling Products.CoolProduct.CoolDocument.CoolDocument.manage_afterAdd
is deprecated when using Five, instead use event subscribers or mark
the class with &amp;lt;five:deprecatedManageAddDelete/&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="using-five-deprecatedmanageadddelete"&gt;
&lt;h1&gt;&lt;a name="using-five-deprecatedmanageadddelete"&gt;Using five:deprecatedManageAddDelete&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The simplest thing you can do to deal with the deprecation warnings, and
have correct behavior, is to add in your products a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;configure.zcml&lt;/span&gt;&lt;/tt&gt;
file containing:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;configure
    xmlns=&amp;quot;http://namespaces.zope.org/zope&amp;quot;
    xmlns:five=&amp;quot;http://namespaces.zope.org/five&amp;quot;&amp;gt;

  &amp;lt;five:deprecatedManageAddDelete
      class=&amp;quot;Products.CoolProduct.CoolDocument.CoolDocument&amp;quot;/&amp;gt;

&amp;lt;/configure&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This tells Zope that you acknowledge that your class contains deprecated
methods, and ask it to still call them in the proper manner. So Zope
will be sending events when an object is added, for instance, and in
addition call your old &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterAdd&lt;/span&gt;&lt;/tt&gt; method.&lt;/p&gt;
&lt;p&gt;One subtlety here is that you may have to modify you methods to just do
their work, and not call their super class. This is necessary because
proper events are already dispatched to all relevant classes, and the
work of the super class will be done trough events, you must not redo it
by hand. If you call the super class, you will get a warning, saying for
instance:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
CoolDocument.manage_afterAdd is deprecated and will be removed in
Zope 2.11, you should use an IObjectAddedEvent subscriber instead.
&lt;/pre&gt;
&lt;p&gt;The fact that you must &amp;quot;just do your work&amp;quot; is especially important for
the rare cases where people subclass the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterAdd&lt;/span&gt;&lt;/tt&gt; of object
managers like folders, and decided to reimplement recursion into the
children themselves. If you do that, then there will be two recursions
going on in parallel, the one done by events, and the one done by your
code. This would be bad.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="using-subscribers"&gt;
&lt;h1&gt;&lt;a name="using-subscribers"&gt;Using subscribers&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In the long run, and before Zope 2.11 where &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterAdd&lt;/span&gt;&lt;/tt&gt; and
friends will be removed, you will want to use proper subscribers.&lt;/p&gt;
&lt;p&gt;First, you'll have to write a subscriber that &amp;quot;does the work&amp;quot;, for
instance:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
def addedCoolDocument(ob, event):
    &amp;quot;&amp;quot;&amp;quot;A Cool Document was added to a container.&amp;quot;&amp;quot;&amp;quot;
    self.mangled_path = mangle('/'.join(self.getPhysicalPath()))
&lt;/pre&gt;
&lt;p&gt;Note that we're not calling the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;portal_cool&lt;/span&gt;&lt;/tt&gt; tool anymore, because
presumably this tool will also be modified to do its work through
events, and will have a similar subscriber doing the necessary
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;registerCool&lt;/span&gt;&lt;/tt&gt;. Note also that here we don't care about the event, but
in more complex cases we would.&lt;/p&gt;
&lt;p&gt;Now we have to register our subscriber for our object. To do that, we
need to &amp;quot;mark&amp;quot; our object through an interface. We can define in our
product's &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;interfaces.py&lt;/span&gt;&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
from zope.interface import Interface, Attribute

class ICoolDocument(Interface):
    &amp;quot;&amp;quot;&amp;quot;Cool Document.&amp;quot;&amp;quot;&amp;quot;
    mangled_path = Attribute(&amp;quot;Our mangled path.&amp;quot;)
    ...
&lt;/pre&gt;
&lt;p&gt;Then the class CoolDocument is marked with this interface:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
from zope.interface import implements
from Products.CoolProduct.interfaces import ICoolDocument
class CoolDocument(...):
    implements(ICoolDocument)
    ...
&lt;/pre&gt;
&lt;p&gt;Finally we must link the event and the interface to the subscriber using
zcml, so in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;configure.zcml&lt;/span&gt;&lt;/tt&gt; we'll add:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
...
  &amp;lt;subscriber
      for=&amp;quot;Products.CoolProduct.interfaces.ICoolDocument
           zope.app.container.interfaces.IObjectAddedEvent&amp;quot;
      handler=&amp;quot;Products.CoolProduct.CoolDocument.addedCoolDocument&amp;quot;
      /&amp;gt;
...
&lt;/pre&gt;
&lt;p&gt;And that's it, everything is plugged. Note that IObjectAddedEvent takes
care of both &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterAdd&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterClone&lt;/span&gt;&lt;/tt&gt;, as it's sent
whenever a new object is placed into a container. However this won't
take care of moves and renamings, we'll see below how to do that.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="event-dispatching"&gt;
&lt;h1&gt;&lt;a name="event-dispatching"&gt;Event dispatching&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;When an IObjectEvent (from which all the events we're talking here
derive) is initially sent, it concerns one object. For instance, a
specific object is removed. The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;event.object&lt;/span&gt;&lt;/tt&gt; attribute is this
object.&lt;/p&gt;
&lt;p&gt;To be able to know about removals, we could just subscribe to the
appropriate event using a standard event subscriber. In that case, we'd
have to filter &amp;quot;by hand&amp;quot; to check if the object removed is of the type
we're interested in, which would be a chore. In addition, any subobjects
of the removed object wouldn't know what happens to them, and for
instance they wouldn't have any way of doing some cleanup before they
disappear.&lt;/p&gt;
&lt;p&gt;To solve these two problems, Zope 3 has an additional mechanism by which
any IObjectEvent is redispatched using multi-adapters of the form &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;(ob,&lt;/span&gt;
&lt;span class="pre"&gt;event)&lt;/span&gt;&lt;/tt&gt;, so that a subscriber can be specific about the type of object
it's interested in. Furthermore, this is done recursively for all
sublocations &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ob&lt;/span&gt;&lt;/tt&gt; of the initial object. The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;event&lt;/span&gt;&lt;/tt&gt; won't change
though, and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;event.object&lt;/span&gt;&lt;/tt&gt; will still be the original object for which
the event was initially sent (this corresponds to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;self&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;item&lt;/span&gt;&lt;/tt&gt;
in the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_afterAdd&lt;/span&gt;&lt;/tt&gt; method -- &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;self&lt;/span&gt;&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ob&lt;/span&gt;&lt;/tt&gt;, and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;item&lt;/span&gt;&lt;/tt&gt; is
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;event.object&lt;/span&gt;&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;Understanding the hierarchy of events is important to see how to
subscribe to them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;IObjectEvent is the most general. Any event focused on an object
derives from this.&lt;/li&gt;
&lt;li&gt;IObjectMovedEvent is sent when an object changes location or is
renamed. It is quite general, as it also encompasses the case where
there's no old location (addition) or no new location (removal).&lt;/li&gt;
&lt;li&gt;IObjectAddedEvent and IObjectRemovedEvent both derive from
IObjectMovedEvent.&lt;/li&gt;
&lt;li&gt;IObjectCopiedEvent is sent just after an object copy is made, but
this doesn't mean the object has been put into its new container yet,
so it doesn't have a location.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are only a few basic use cases about what one wants to do with
respect to events (but you might want to read the full story in
Five/tests/event.txt).&lt;/p&gt;
&lt;p&gt;The first use case is the one where the object has to be aware of its
path, like in the CoolDocument example above. That's strictly a Zope 2
concern, as Zope 3 has others ways to deal with this.&lt;/p&gt;
&lt;p&gt;In Zope 2 an object has a new path through creation, copy or move
(rename is a kind of move). The events sent during these three
operations are varied: creation sends IObjectAddedEvent, copy sends
IObjectCopiedEvent then IObjectAddedEvent, and move sends
IObjectMovedEvent.&lt;/p&gt;
&lt;p&gt;So to react to new paths, we have to subscribe to IObjectMovedEvent, but
this will also get us any IObjectRemovedEvent, which we'll have to
filter out by hand (this is unfortunate, and due to the way the Zope 3
interface hierarchy is organized). So to fix the CoolDocument
configuration we have to add:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
def movedCoolDocument(ob, event):
    &amp;quot;&amp;quot;&amp;quot;A Cool Document was moved.&amp;quot;&amp;quot;&amp;quot;
    if not IObjectRemovedEvent.providedBy(event):
        addedCoolDocument(ob, event)
&lt;/pre&gt;
&lt;p&gt;And replace the subscriber with:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
...
  &amp;lt;subscriber
      for=&amp;quot;Products.CoolProduct.interfaces.ICoolDocument
           zope.app.container.interfaces.IObjectMovedEvent&amp;quot;
      handler=&amp;quot;Products.CoolProduct.CoolDocument.movedCoolDocument&amp;quot;
      /&amp;gt;
...
&lt;/pre&gt;
&lt;p&gt;The second use case is when the object has to do some cleanup when it is
removed from its parent. This used to be in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;manage_beforeDelete&lt;/span&gt;&lt;/tt&gt;, now
we can do the work in a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;removedCoolDocument&lt;/span&gt;&lt;/tt&gt; method and just
subscribe to IObjectRemovedEvent. But wait, this won't take into account
moves... So in the same vein as above, we would have to write:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
def movedCoolDocument(ob, event):
    &amp;quot;&amp;quot;&amp;quot;A Cool Document was moved.&amp;quot;&amp;quot;&amp;quot;
    if not IObjectRemovedEvent.providedBy(event):
        addedCoolDocument(ob, event)
    if not IObjectAddedEvent.providedBy(event):
        removedCoolDocument(ob, event)
&lt;/pre&gt;
&lt;p&gt;The third use case is when your object has to stay registered with some
tool, for instance indexed in a catalog, or as above registered with
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;portal_cool&lt;/span&gt;&lt;/tt&gt;. Here we have to know the old object's path to
unregister it, so we have to be called &lt;em&gt;before&lt;/em&gt; it is removed. We'll use
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;IObjectWillBe...&lt;/span&gt;&lt;/tt&gt; events, that are sent before the actual operations take place:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
from OFS.interfaces import IObjectWillBeAddedEvent
def beforeMoveCoolDocument(ob, event):
    &amp;quot;&amp;quot;&amp;quot;A Cool Document will be moved.&amp;quot;&amp;quot;&amp;quot;
    if not IObjectWillBeAddedEvent.providedBy(event):
        getToolByName(ob, 'portal_cool').unregisterCool(ob)

def movedCoolDocument(ob, event):
    &amp;quot;&amp;quot;&amp;quot;A Cool Document was moved.&amp;quot;&amp;quot;&amp;quot;
    if not IObjectRemovedEvent.providedBy(event):
        getToolByName(ob, 'portal_cool').registerCool(ob)
    ...
&lt;/pre&gt;
&lt;p&gt;And use an additional subscriber:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
...
  &amp;lt;subscriber
      for=&amp;quot;Products.CoolProduct.interfaces.ICoolDocument
           OFS.interfaces.IObjectWillBeMovedEvent&amp;quot;
      handler=&amp;quot;Products.CoolProduct.CoolDocument.beforeMoveCoolDocument&amp;quot;
      /&amp;gt;
...
&lt;/pre&gt;
&lt;p&gt;This has to be done if the tool cannot react by itself to objects being
added and removed, which obviously would be better as it's ultimately
the tool's responsibility and not the object's.&lt;/p&gt;
&lt;p&gt;Note that if having tests like:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
if not IObjectWillBeAddedEvent.providedBy(event):
if not IObjectRemovedEvent.providedBy(event):
&lt;/pre&gt;
&lt;p&gt;seems cumbersome (and backwards), it is also possible to check what kind
of event you're dealing with using:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
if event.oldParent is not None:
if event.newParent is not None:
&lt;/pre&gt;
&lt;p&gt;(However be careful, the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;oldParent&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;newParent&lt;/span&gt;&lt;/tt&gt; are the old and
new parents &lt;em&gt;of the original object&lt;/em&gt; for which the event was sent, not
of the one to which the event was redispatched using the
multi-subscribers we have registered.)&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;IObjectWillBe...&lt;/span&gt;&lt;/tt&gt; events are specific to Zope 2 (and imported
from &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;OFS.interfaces&lt;/span&gt;&lt;/tt&gt;). Zope 3 doesn't really need them, as object
identity is often enough.&lt;/p&gt;
&lt;/div&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_11_08_events-in-zope-2-9</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_11_08_events-in-zope-2-9/atom?2005_11_08_events-in-zope-2-9"
        title="Edit Here - Events in Zope 2.9" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">CPS Second Bug Day Wrapup</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_10_28_cps-second-bug-day" />
  <issued>2005-10-28T09:54:20Z</issued>
  <modified>2005-10-28T09:54:20Z</modified>
  <created>2005-10-28T09:54:20Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>cps</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
This bug day was announced on short notice, we we still managed to kill 26 bugs (while 9 new were opened). That's good work!


Because there are still 84 active tickets for CPS 3.4 (some are only details of course), we've decided to release a CPS 3.3.7 in the meantime, probably early next week. And we'll keep doing bug days, I propose to have them every Thursday until CPS 3.4 is finally ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;
This bug day was announced on short notice, we we still managed to kill 26 bugs (while 9 new were opened). That's good work!
&lt;/p&gt;
&lt;p&gt;
Because there are still 84 active tickets for CPS 3.4 (some are only details of course), we've decided to release a CPS 3.3.7 in the meantime, probably early next week. And we'll keep doing bug days, I propose to have them every Thursday until CPS 3.4 is finally released.
&lt;/p&gt;
</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_10_28_cps-second-bug-day</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_10_28_cps-second-bug-day/atom?2005_10_28_cps-second-bug-day"
        title="Edit Here - CPS Second Bug Day Wrapup" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">CPS 3.3.6 released</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_09_21_cps-3-3-6-released" />
  <issued>2005-09-21T16:20:32Z</issued>
  <modified>2005-09-21T16:20:32Z</modified>
  <created>2005-09-21T16:19:56Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>cps</dc:subject>
  
  
    <dc:subject>five</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
    <dc:subject>zope3</dc:subject>
  
  
  <summary type="text/html" mode="escaped">CPS 3.3.6 has just been released.
You'll find download links in the "Quick Download" box of http://www.cps-project.org.
This release contains mainly bugfixes, and some speed improvements. It also bundles for the first time CPSSharedCalendar (successor to CPSCalendar) and CPSMailAccess (sucessor to CPSWebMail), two components heavily based on Five.</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;CPS 3.3.6 has just been released.&lt;/p&gt;
&lt;p&gt;You'll find download links in the "Quick Download" box of &lt;a href="http://www.cps-project.org"&gt;http://www.cps-project.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This release contains mainly bugfixes, and some speed improvements. It also bundles for the first time CPSSharedCalendar (successor to CPSCalendar) and CPSMailAccess (sucessor to CPSWebMail), two components heavily based on Five.&lt;/p&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_09_21_cps-3-3-6-released</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_09_21_cps-3-3-6-released/atom?2005_09_21_cps-3-3-6-released"
        title="Edit Here - CPS 3.3.6 released" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">CPS Bug Day Wrapup</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_09_16_cps-bug-day-wrapup" />
  <issued>2005-09-16T10:31:01Z</issued>
  <modified>2005-09-16T10:31:01Z</modified>
  <created>2005-09-16T10:28:06Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>cps</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
The CPS bug day this Wednesday was quite productive. A number of actual bugs were fixed, but more importantly a lot of bug triage and sorting happened, to determine what was urgent (going into CPS 3.3.6), what was necessary for the next stable CPS 3.4 release, and what could be postponed to a later development cycle (CPS 3.5). The Timeline for Wednesday show 65 bugs resolved (fixed or closed). ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;
The CPS bug day this Wednesday was quite productive. A number of actual bugs were fixed, but more importantly a lot of bug triage and sorting happened, to determine what was urgent (going into CPS 3.3.6), what was necessary for the next stable CPS 3.4 release, and what could be postponed to a later development cycle (CPS 3.5). The &lt;a href="http://svn.nuxeo.org/trac/pub/timeline?from=09%2F14%2F05&amp;daysback=0&amp;ticket=on"&gt;Timeline for Wednesday&lt;/a&gt; show 65 bugs resolved (fixed or closed). In addition to these, several hundreds have been retargetted or cleaned up.
&lt;/p&gt;
&lt;p&gt;
I'm now confident that CPS 3.3.6 will get released within a week. Before CPS 3.4 we still have a number of important things to do though, so there may be a need for a CPS 3.3.7 which would serve as some kind of prerelease, we'll really need "in the wild" validating of some important features such as the CMFSetup-based installation and import/export tools.
&lt;/p&gt;
&lt;p&gt;
The schedule for the remaining work before CPS 3.4 is really conditionned by the availability of the developers. We still expect CPS 3.4 to be released around mid-october.
&lt;/p&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_09_16_cps-bug-day-wrapup</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_09_16_cps-bug-day-wrapup/atom?2005_09_16_cps-bug-day-wrapup"
        title="Edit Here - CPS Bug Day Wrapup" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Object-Relational mapping in Zope</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_08_11_object_relational" />
  <issued>2005-08-11T16:51:42Z</issued>
  <modified>2005-08-11T16:51:42Z</modified>
  <created>2005-08-11T15:26:50Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>cps</dc:subject>
  
  
    <dc:subject>python</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
    <dc:subject>zope3</dc:subject>
  
  
  <summary type="text/html" mode="escaped"> I've been interested in object-relational mapping in Zope for a
while. I see this as the keystone of a proper enterprise-grade
application server, and I've been investigating existing tools and what
can be done with them. Here's a quick rundown. 

ZSQL methods

 Using ZSQL methods (a standard feature of Zope), you can have your
application talk to an SQL database, but you're not really ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt; I've been interested in object-relational mapping in Zope for a
while. I see this as the keystone of a proper enterprise-grade
application server, and I've been investigating existing tools and what
can be done with them. Here's a quick rundown. &lt;/p&gt;

&lt;h3&gt;ZSQL methods&lt;/h3&gt;

&lt;p&gt; Using ZSQL methods (a standard feature of Zope), you can have your
application talk to an SQL database, but you're not really dealing with
object-relational mapping, there are no transparently persistent
objects. So let's skip it. &lt;/p&gt;

&lt;h3&gt;SQLObject / sqlos&lt;/h3&gt;

&lt;p&gt; &lt;a href="http://sqlobject.org/"&gt;SQLObject&lt;/a&gt; is a pure python
mapper, and it is used in Zope 3 through &lt;a
href="http://codespeak.net/z3/sqlos/"&gt;sqlos&lt;/a&gt;. They provides
declarative mapping for your classes where you can write for instance:
&lt;/p&gt;

&lt;pre&gt;
class Person(SQLOS):
    implements(IPerson)
    _columns = [StringCol("username", length=20, notNull=True),
                StringCol("firstname", length=20, notNull=True),
                StringCol("lastname", length=20, notNull=True)]
&lt;/pre&gt;

&lt;p&gt; Then any instance of a Person will actually be stored in SQL behind
your back. A unique id is generated for each Person and also stored in
SQL. There are various facilities to provide relations between
tables, and map them to lists in the python objects. &lt;/p&gt;

&lt;h3&gt;Archetypes + SQLStorage&lt;/h3&gt;

&lt;p&gt; &lt;a
href="http://plone.sourceforge.net/archetypes/sqlstorage-howto.html"&gt;SQLStorage&lt;/a&gt;
is an &lt;a
href="http://plone.org/documentation/archetypes/"&gt;Archetypes&lt;/a&gt; storage
that uses SQL as a backend. You can write an Archetypes schema such as: &lt;/p&gt;

&lt;pre&gt;
schema = BaseSchema + Schema((
    StringField("username", required=1, primary=1, searchable=1,
                storage=PostgreSQLStorage(),
                 index="FieldIndex",
                ),
    StringField("firstname", required=1,
                storage=PostgreSQLStorage(),
                ),
    StringField("lastname", required=1,
                storage=PostgreSQLStorage(),
                ),
    )) + TemplateMixin.schema

class PersonSQL(TemplateMixin, BaseContent):
    archetype_name = "Person SQL"
    schema = schema
&lt;/pre&gt;

&lt;p&gt; SQLStorage relies on the Archetypes UIDs to uniquely identify
objects. A Relation field can be used to have relations to other objects.
Note that Archetypes objects stored through SQLStorage still have a
presence in the ZODB, which means it's not a solution if you totally
want to get rid of Data.fs bloat. &lt;/p&gt;

&lt;p&gt; As you can see in the way things are declared, both SQLObject and
Archetypes require you to specify &lt;em&gt;in your code&lt;/em&gt; that you will
use SQL for some objects. Things are not "transparent" from the
programmer's point of view. &lt;/p&gt;

&lt;h3&gt;Ape&lt;/h3&gt;

&lt;p&gt; &lt;a href=""&gt;Ape&lt;/a&gt; (Adaptable Persistence Engine) is a framework to
do object-relational mapping at a lower level than the above two
solutions, because it works at the ZODB Storage level. Ape is used as a
ZODB Mount Point inside Zope. In fact, Ape is not tied to SQL but is
designed to do configurable and flexible mapping to anything; storing to
the filesystem is another option provided by default. &lt;/p&gt;

&lt;p&gt; Ape relies on the ZODB framework, and especially its classes for
persistence and transaction management, backed by the storage APIs
themselves. This means that from the programmer's point of view, there's
no difference when using Ape than when using a FileStorage or a ZEO
ClientStorage. Everything is transparent. &lt;/p&gt;

&lt;p&gt; This is a big advantage for the programmer, but the downside is that
the structure of the tables in the SQL database is chosen by the
framework. However Ape's default SQL mapper already tries hard to
provide data mapping in a natural way; for instance all properties are
made available in a natural manner, object titles or containment
relationship are also naturally expressed. &lt;/p&gt;

&lt;h3&gt;Hornet&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://plone.org/products/hornet/"&gt;Hornet&lt;/a&gt; is an SQL
bridge (alpha software for now) that also works at the ZODB layer. In
contrast to Ape, it is much more geared toward existing datasets, or
regular SQL access to tables. It requires you to define schemas in code
too, but once this is done object access is totally transparent, as in
Ape. You have to use code like:&lt;/p&gt;

&lt;pre&gt;
PySchema(fieldsets=(
    FieldSet("employee_type", label="Employee Type", widgets=(
        StringWidget("code", label="Employee Code"),
        StringWidget("description", label="Description"),
        )),
    ))
&lt;/pre&gt;

&lt;p&gt; This is then used by the mount point and the underlying Hornet
framework for a given table to decide how to map table lines to objects.
(The schema is also used to autogenerate forms.) &lt;/p&gt;

&lt;h3&gt;I want more&lt;/h3&gt;

&lt;p&gt; To me Hornet and Ape are promising because I believe they integrate
at the right level. Ape is better because it doesn't require explicit
schema declaration, and that's very important when you have flexible
objects where the users add new fields on document instances (which
happens all the time in CPS using FlexibleTypeInformation-based content
objects). &lt;/p&gt;

&lt;p&gt; I believe a large part of the success of the infamous Rails has been
that it makes it trivial to interface to an existing SQL database,
provided it's regularly named. And I want to bring Zope to that level,
but that's just going to be a side effect of a number of other goals. &lt;/p&gt;

&lt;p&gt; First, I want to get rid of the catalog and move it to its proper
place, which is in a relational database. The ZCatalog is a hack (a
successful one I must admit) that tries to bring into the ZODB world
something that has been working much better for ages in the relational
world. The ZCatalog indexes use a truly gigantic number of small
persistent objects to work. Querying an index trashes the ZODB cache
which could be used for better things (to cache the objects the user is
really accessing). Also the ZCatalog fails to provide any relational
features, like JOIN queries. The sorting is weak (you cannot sort on
something that's in a full-text index without adding another index).
Finally, the "metadata" is duplicating lots information that can be
found elsewhere. &lt;/p&gt;

&lt;p&gt; If you store your data in SQL, then you can dump the ZCatalog
implementation and delegate indexing and searching to SQL. &lt;/p&gt;

&lt;p&gt; Second, I want to store blobs in the filesystem. This can be done at
the application level by various products such as CPS DiskFileField,
Archetypes ExternalStorage, chrism's &lt;a
href="http://www.plope.com/software/blob/"&gt;Blob product&lt;/a&gt;, and others.
It can also be done transparently at the ZODB storage level using Ape,
and that's a much simpler way to do it. &lt;/p&gt;

&lt;p&gt; Finally I want my application-specific data (document metadata,
document hierarchy, versioning information, various customer specific
record-like objects, user definitions, access rights, etc) to be stored
in SQL because most of them really live naturally in SQL tables. And
because I want to do aggregates on them, like sums and means. &lt;p&gt;

&lt;p&gt; To achieve this, I plan on using the most flexible (and underused)
framework available, which is Ape. I'll write various classifiers, and
mappers so that a typical CMF or CPS site can be mapped naturally to
SQL. I'll also replace the catalog by an implementation that does SQL
queries. This will not be a simple endeavour, but I feel this is the
only way to get what I truly need in the end, without sacrifying any
flexibility. &lt;/p&gt;

&lt;p&gt; If Ape proves to hard to work with (because it imposes its own
framework of mapping), I'll go the Hornet way of writing a storage directly, with
flexible enough policies for the mapping to SQL or the filesystem (or LDAP for that
matter). &lt;/p&gt;

&lt;p&gt; It goes without saying that this will apply to Zope 3, because
that's part of what I think an ECM system should provide. But there's no
reason not to make it work in Zope 2, and that's probably where I'll
start. &lt;/p&gt;

&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; I was asked how this would fit with the "do things in python" philosophy that Martijn has been rightly pushing. Ape is first a pure python library that provides a new database class for use with ZODB (which itself can be considered independent of Zope). Ape also provides Zope-specific mappers that know how to best deal with a number Zope-specific classes. Whenever possible, I'd like to keep to that organisation (also keep in mind that a good separation will make it reusable both by Zope 2 and Zope 3).
&lt;/p&gt;
</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_08_11_object_relational</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_08_11_object_relational/atom?2005_08_11_object_relational"
        title="Edit Here - Object-Relational mapping in Zope" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">ZODB presentation and tips</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_08_03_zodb_presentation_tips" />
  <issued>2005-08-03T11:52:31Z</issued>
  <modified>2005-08-03T11:52:31Z</modified>
  <created>2005-08-03T11:52:30Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>zope</dc:subject>
  
  
    <dc:subject>zope3</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
Chris McDonough has a nice presentation of ZODB, with some tips about how to make it perform better. One I hadn't read about before is the cacheMinimize in the middle of big transactions; I'll have to check how it performs in some situations.


http://www.plope.com/static/presentations/zodb.pdf

</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;
Chris McDonough has a nice presentation of ZODB, with some tips about how to make it perform better. One I hadn't read about before is the &lt;code&gt;cacheMinimize&lt;/code&gt; in the middle of big transactions; I'll have to check how it performs in some situations.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.plope.com/static/presentations/zodb.pdf"&gt;http://www.plope.com/static/presentations/zodb.pdf&lt;/a&gt;
&lt;/p&gt;
</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_08_03_zodb_presentation_tips</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_08_03_zodb_presentation_tips/atom?2005_08_03_zodb_presentation_tips"
        title="Edit Here - ZODB presentation and tips" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">A comparison of indexers</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_06_30_comparison_indexers" />
  <issued>2005-06-30T17:59:28Z</issued>
  <modified>2005-06-30T17:59:28Z</modified>
  <created>2005-06-30T17:59:28Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>python</dc:subject>
  
  
    <dc:subject>zope3</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
http://www.let.rug.nl/~gosse/Imix/clin04_tiedemann.pdf is a poster comparing several Information Retrieval (IR) engines, among them Lucene and Xapian.


This analysis could be helpful in choosing something nice for the Z3 ECM.


</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;
&lt;a href="http://www.let.rug.nl/~gosse/Imix/clin04_tiedemann.pdf"&gt;http://www.let.rug.nl/~gosse/Imix/clin04_tiedemann.pdf&lt;/a&gt; is a poster comparing several Information Retrieval (IR) engines, among them Lucene and Xapian.
&lt;/p&gt;
&lt;p&gt;
This analysis could be helpful in choosing something nice for the Z3 ECM.
&lt;/p&gt;

</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_06_30_comparison_indexers</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_06_30_comparison_indexers/atom?2005_06_30_comparison_indexers"
        title="Edit Here - A comparison of indexers" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Compiling python 2.3.5 on Mac OS X Tiger</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_05_21_compiling_python_2_3_5" />
  <issued>2005-05-30T12:22:21Z</issued>
  <modified>2005-05-30T12:22:21Z</modified>
  <created>2005-05-21T00:57:21Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>python</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
  Tiger comes with python 2.3.5 bundled, which is nice, but sometimes you want
  to recompile it, or you want to add site-packages to it without disturbing
  the standard OS installation. Here's what I had to do to compile it, and
  python-ldap with it.

Building python 2.3.5:

./configure
vi pyconfig.h
  #undef _POSIX_C_SOURCE
  #undef _XOPEN_SOURCE
  #define ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">&lt;p&gt;
  Tiger comes with python 2.3.5 bundled, which is nice, but sometimes you want
  to recompile it, or you want to add site-packages to it without disturbing
  the standard OS installation. Here's what I had to do to compile it, and
  python-ldap with it.
&lt;/p&gt;
&lt;p&gt;Building python 2.3.5:&lt;/p&gt;
&lt;pre&gt;
./configure
vi pyconfig.h
  #undef _POSIX_C_SOURCE
  #undef _XOPEN_SOURCE
  #define HAVE_BROKEN_POSIX_SEMAPHORES
  #define SETPGRP_HAVE_ARG
make
make test
sudo make install
&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;Updated:&lt;/b&gt; Added commenting-out of _POSIX_C_SOURCE, otherwise &lt;code&gt;ESHUTDOWN&lt;/code&gt; cannot be imported from errno (which makes asyncore fail). Added &lt;code&gt;SETPGRP_HAVE_ARG&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;Building Berkeley DB 4.3.28 (needed by OpenLDAP):&lt;/p&gt;
&lt;pre&gt;
cd build_unix
../dist/configure
make
sudo make install
&lt;/pre&gt;
&lt;p&gt;Building OpenLDAP 2.2.26:&lt;/p&gt;
&lt;pre&gt;
CPPFLAGS=-I/usr/local/BerkeleyDB.4.3/include LDFLAGS=-L/usr/local/BerkeleyDB.4.3/lib ./configure
vi config.status
  # replace s%@LIBS@%%g with:
  s%@LIBS@%-lresolv%g
./config.status
make depend
make
sudo make install
&lt;/pre&gt;
&lt;p&gt;Building python-ldap 2.0.7:&lt;/p&gt;
&lt;pre&gt;
vi setup.cfg
  library_dirs = /usr/local/lib
  include_dirs = /usr/local/include
  # comment libs = sasl2 in libs:
  libs = ldap_r lber ssl crypto
/usr/local/bin/python2.3 setup.py build
sudo /usr/local/bin/python2.3 setup.py install
&lt;/pre&gt;</content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_05_21_compiling_python_2_3_5</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_05_21_compiling_python_2_3_5/atom?2005_05_21_compiling_python_2_3_5"
        title="Edit Here - Compiling python 2.3.5 on Mac OS X Tiger" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">CMFSetup for CPS</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_04_03_cmfsetup_for_cps" />
  <issued>2005-04-03T13:46:42Z</issued>
  <modified>2005-04-03T13:46:42Z</modified>
  <created>2005-04-03T13:46:41Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>cps</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
  I've started playing with CMFSetup to improve importing and exporting the
  configuration of a CPS site.
  
  CMFSetup is a framework that describes the series of steps needed to setup a
  CMF site, for instance "setup the actions tool", "setup the workflows", etc.
  Each step is implemented by code that looks up the details of the
  configuration in XML files. The CMF Setup Tool itself ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">
  I've started playing with CMFSetup to improve importing and exporting the
  configuration of a CPS site.&lt;br /&gt;
  &lt;br /&gt;
  CMFSetup is a framework that describes the series of steps needed to setup a
  CMF site, for instance "setup the actions tool", "setup the workflows", etc.
  Each step is implemented by code that looks up the details of the
  configuration in XML files. The CMF Setup Tool itself allows you to execute
  steps individually (either in import or export mode), to make snapshots of
  the existing state of a site, to compare them, to revert to any of them, and
  of course to save the complete configuration to a file.&lt;br /&gt;
  &lt;br /&gt;
  Yesterday I wrote some code to do the import/export for the directories
  configuration. I'll do the same soon for schemas and layouts, and then for
  the rest of the CPS tools. The goal is to be able to instanciate a CPS site
  entirely through this mechanism, which means that all the configuration
  would be in XML files.&lt;br /&gt;
  &lt;br /&gt;
  Amon the remaining questions is, what to do about content, and what to do
  about things that could be considered configuration but could also be
  considered content. Instances of the latter are the content of directories
  (ZODB directories for instance). For pure content stuff, I think a global
  XML import/export (maybe optionaly retaining only the folder structure but
  not the documents) can be done.&lt;br /&gt;
  &lt;br /&gt;
  The advantage of using CMFSetup over CPSIO is that CMFSetup brings a very
  rich framework for comparison and snapshots. One disadvantage of CMFSetup is
  that parsing the XML files on import is largely ad-hoc, and painful to code.
  Using a library like elementtree (like CPSIO does) would improve the process
  a lot, so I'll play with that.&lt;br /&gt;
  &lt;br /&gt;
  One nice thing in coding CMFSetup import/export handlers for CPS is that
  CPSIO has already done this once, so all the code to introspect or recreate
  objects can be reused, or at least used as an inspiration. Nevertheless it's
  a lot of work that will have to be done piecewise.&lt;br /&gt;
  &lt;br /&gt;
 </content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_04_03_cmfsetup_for_cps</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_04_03_cmfsetup_for_cps/atom?2005_04_03_cmfsetup_for_cps"
        title="Edit Here - CMFSetup for CPS" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Paris Sprint, Day #2</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_03_16_paris_sprint_day_2" />
  <issued>2005-03-16T09:37:30Z</issued>
  <modified>2005-03-16T09:37:30Z</modified>
  <created>2005-03-16T09:37:30Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>five</dc:subject>
  
  
    <dc:subject>sprint</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
    <dc:subject>zope3</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
  After a first day of setting up everybody and finding intersting subjects to
  work on, I spent today working on the Five-2.8 integration.
  
  One of my goals was to remove monkey-patching, which is mainly done except
  that Five has a need for an unrestricted TALES engine, but Zope's TALES
  engine is very not modular and very difficult to subclass. Five, to
  avoid copying code, is ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">
  After a first day of setting up everybody and finding intersting subjects to
  work on, I spent today working on the Five-2.8 integration.&lt;br /&gt;
  &lt;br /&gt;
  One of my goals was to remove monkey-patching, which is mainly done except
  that Five has a need for an unrestricted TALES engine, but Zope's TALES
  engine is very &lt;i&gt;not&lt;/i&gt; modular and very difficult to subclass. Five, to
  avoid copying code, is actually using code from Dieter Maurer that copies
  function objects and rebind their arguments to add new definitions to the
  scope... a nice hack but maybe something we can get rid of.&lt;br /&gt;
  &lt;br /&gt;
  The goal is to release a beta of Zope 2.8 that includes Five (and the needed
  Zope X3 components) as soon as possible, possibly by the end of the week
  (but don't hold your breath).&lt;br /&gt;
  &lt;br /&gt;
  This will be very useful because it will put Zope 3 technologies directly in
  the hands of Zope developers, without any additional installs. That's
  crucial to gain acceptance and visibility, and more importantly to gain
  developers that will be more willing to work with Zope 3.&lt;br /&gt;
 </content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_03_16_paris_sprint_day_2</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_03_16_paris_sprint_day_2/atom?2005_03_16_paris_sprint_day_2"
        title="Edit Here - Paris Sprint, Day #2" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Apache + mod_python + ZEO</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_02_23_apache_mod_python_zeo" />
  <issued>2005-03-08T01:20:37Z</issued>
  <modified>2005-03-08T01:20:37Z</modified>
  <created>2005-02-23T18:34:03Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
  <summary type="text/html" mode="escaped">
  Pascal Peregrina from lastminute.com is experimenting with
  using Apache + mod_python as ZEO clients.
   
   Apparently he has good results.
   
   http://www.zope.org/Members/pperegrina/ZopeHandler
   
   
  http://mail.zope.org/pipermail/zope/2005-February/156379.html
   
  http://mail.zope.org/pipermail/zope/2005-February/156384.html
   
 </summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">
  Pascal Peregrina from lastminute.com is experimenting with
  using Apache + mod_python as ZEO clients.&lt;br /&gt;
   &lt;br /&gt;
   Apparently he has good results.&lt;br /&gt;
   &lt;br /&gt;
   &lt;a
  href="http://www.zope.org/Members/pperegrina/ZopeHandler"&gt;http://www.zope.org/Members/pperegrina/ZopeHandler&lt;/a&gt;&lt;br /&gt;
   &lt;br /&gt;
   &lt;a
  href="http://mail.zope.org/pipermail/zope/2005-February/156379.html"&gt;
  http://mail.zope.org/pipermail/zope/2005-February/156379.html&lt;/a&gt;&lt;br /&gt;
   &lt;a
  href="http://mail.zope.org/pipermail/zope/2005-February/156384.html"&gt;
  http://mail.zope.org/pipermail/zope/2005-February/156384.html&lt;/a&gt;&lt;br /&gt;
   &lt;br /&gt;
 </content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_02_23_apache_mod_python_zeo</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_02_23_apache_mod_python_zeo/atom?2005_02_23_apache_mod_python_zeo"
        title="Edit Here - Apache + mod_python + ZEO" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">DeadlockDebugger 1.0</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_02_23_deadlockdebugger_1_0" />
  <issued>2005-03-08T01:20:39Z</issued>
  <modified>2005-03-08T01:20:39Z</modified>
  <created>2005-02-23T16:27:15Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>zope</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
  This product adds a hook so that a deadlocked Zope process
  can be debugged, by dumping a traceback of all running python
  processes. The dump is sent to the event log (at the DEBUG
  level) and returned to the browser (even though the Zope is
  deadlocked and doesn't answer any other requests!).

  DeadlockDebugger can of course also be used to debug Zope
  in non-deadlock situations, when ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">
  &lt;p&gt;This product adds a hook so that a deadlocked Zope process
  can be debugged, by dumping a traceback of all running python
  processes. The dump is sent to the event log (at the DEBUG
  level) and returned to the browser (even though the Zope is
  deadlocked and doesn't answer any other requests!).&lt;/p&gt;

  &lt;p&gt;DeadlockDebugger can of course also be used to debug Zope
  in non-deadlock situations, when a Zope process is taking a
  long time and you wish to know what code is being
  executed.&lt;br /&gt;
  &lt;/p&gt;
  &lt;a
  href="http://www.zope.org/Members/nuxeo/Products/DeadlockDebugger"&gt;
  http://www.zope.org/Members/nuxeo/Products/DeadlockDebugger&lt;/a&gt;
 </content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_02_23_deadlockdebugger_1_0</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_02_23_deadlockdebugger_1_0/atom?2005_02_23_deadlockdebugger_1_0"
        title="Edit Here - DeadlockDebugger 1.0" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Caching is hard</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_02_23_caching_hard" />
  <issued>2005-03-08T01:20:39Z</issued>
  <modified>2005-03-08T01:20:39Z</modified>
  <created>2005-02-23T13:44:00Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>coding</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
  Caching is a difficult problem, especially when needing to
  correctly invalidate entries. Invalidating is difficult when
  there may be several caches spread accross ZODB connection
  (this is the case for '_v_' attributes), or spread accross ZEO
  clients. Accessing a '_v_' attribute in another ZODB
  connection (i.e., usually, a different thread) is not really
  feasible, and accessing ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">
  Caching is a difficult problem, especially when needing to
  correctly invalidate entries. Invalidating is difficult when
  there may be several caches spread accross ZODB connection
  (this is the case for '_v_' attributes), or spread accross ZEO
  clients. Accessing a '_v_' attribute in another ZODB
  connection (i.e., usually, a different thread) is not really
  feasible, and accessing another ZEO client that may be accross
  the world is impossible directly.&lt;br /&gt;
   &lt;br /&gt;
   Often there are mitigating factors that make the invalidation
  not &lt;i&gt;really&lt;/i&gt; necessary. For instance if the caching is
  only done for the duration of the current request, an
  appropriate cleanup of a '_v_' attribute can be done at the
  end of the request by indirectly using a destructor of the
  request object. This is what is done by the CMF's
  MemberDataTool to hold on to the wrapped member objects for
  the duration of the request, but not longer.&lt;br /&gt;
   &lt;br /&gt;
   A much better way to do coarse-grained invalidation accross
  threads and clients is to do it indirectly, through the use of
  something that can communicate with all these threads and
  clients: a persistent object. The idea is that all cached
  values are cached with a generation number, the generation at
  the moment of their creation. When retrieving a value from the
  cache, the generation it has is compared to the current
  generation, and the cached value is deemed invalid if they
  don't match. This generation number is stored in a persistent
  object (that is therefore visible to all). When an
  invalidation must be done, the persistent generation number is
  incremented (to avoid ConflictError problems, a
  conflict-resistent class such as BTree.Length should be used).
  This solution works when a coarse-grained invalidation is
  suitable, and when don't happen too often.&lt;br /&gt;
   &lt;br /&gt;
   A bug was recently reported to me that involved caching, but
  it turned out to be a different class of problem. The problem
  was that, through a cache, a value holding to persistent
  references was shared among threads. But it is illegal to use
  an object from one ZODB connection in another. When threading
  is involved (which it often is in Zope), problems arise. In
  this bug, the object itself (a user) was not persisted, but it
  had to references to persistent objects (the user folder and a
  directory). In the end I found it better to not store the user
  object in the cache, but just a dictionnary of information
  needed to recreate the user object.&lt;br /&gt;
   &lt;br /&gt;
 </content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_02_23_caching_hard</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_02_23_caching_hard/atom?2005_02_23_caching_hard"
        title="Edit Here - Caching is hard" />
</entry>

  
  
      <entry xmlns="http://purl.org/atom/ns#"
       xmlns:dc="http://purl.org/dc/elements/1.1/">
     
  <title mode="escaped" type="text/html">Debugging deadlocks</title>
  <link rel="alternate" type="text/html"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_02_23_debugging_deadlocks" />
  <issued>2005-03-08T01:20:39Z</issued>
  <modified>2005-03-08T01:20:39Z</modified>
  <created>2005-02-23T11:27:54Z</created>
  <draft xmlns="http://purl.org/atom-blog/ns#">false</draft>
  <author>
    <name>fguillaume</name>
  </author>
  
  
    <dc:subject>python</dc:subject>
  
  
    <dc:subject>zope</dc:subject>
  
  
  <summary type="text/html" mode="escaped">
  I have been confronted to deadlocks in Zope, where the server
  was there without taking any CPU but didn't answer any
  request. It's pretty had to know where to look to find what's
  happenning.
   
   Maxime Yve found a very useful python module: 
  threadframe. Using it, it's possible to dump tracebacks of
  all running threads of a python process. I have a specialized
  dumping product ...</summary>

  <content type="text/html" mode="escaped"
           xml:space="preserve">
  I have been confronted to deadlocks in Zope, where the server
  was there without taking any CPU but didn't answer any
  request. It's pretty had to know where to look to find what's
  happenning.&lt;br /&gt;
   &lt;br /&gt;
   Maxime Yve found a very useful python module: &lt;a
  href="http://www.majid.info/mylos/stories/2004/06/10/threadframe.html"&gt;
  threadframe&lt;/a&gt;. Using it, it's possible to dump tracebacks of
  all running threads of a python process. I have a specialized
  dumping product for a client that I'll make generic soon, to
  debug any Zope.&lt;br /&gt;
   &lt;br /&gt;
 </content>

  <id>tag:blogs.nuxeo.com:sections:blogs:florent_guillaume:2005_02_23_debugging_deadlocks</id>
  <link rel="service.edit" type="application/atom+xml"
        href="http://blogs.nuxeo.com/sections/blogs/florent_guillaume/2005_02_23_debugging_deadlocks/atom?2005_02_23_debugging_deadlocks"
        title="Edit Here - Debugging deadlocks" />
</entry>

  

</feed>
