[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/RDB - DatabaseException.py:1.1 ISQLCommand.py:1.1 SQLCommand.py:1.1 configure.zcml:1.1 IConnectionService.py:1.3 ICursor.py:1.2 IDBIConnection.py:1.3 IDBICursor.py:1.3 IDBITypeInfo.py:1.2 IDBITypeInfoProvider.py:1.2 IResultSet.py:1.4 IZopeConnection.py:1.3 IZopeCursor.py:1.3 IZopeDatabaseAdapter.py:1.3 ResultSet.py:1.3 Row.py:1.3 Util.py:1.3 ZopeConnection.py:1.2 ZopeCursor.py:1.2 ZopeDBTransactionManager.py:1.2 ZopeDatabaseAdapter.py:1.3

Stephan Richter srichter@cbu.edu
Wed, 10 Jul 2002 19:37:27 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/App/RDB
In directory cvs.zope.org:/tmp/cvs-serv2804

Modified Files:
	IConnectionService.py ICursor.py IDBIConnection.py 
	IDBICursor.py IDBITypeInfo.py IDBITypeInfoProvider.py 
	IResultSet.py IZopeConnection.py IZopeCursor.py 
	IZopeDatabaseAdapter.py ResultSet.py Row.py Util.py 
	ZopeConnection.py ZopeCursor.py ZopeDBTransactionManager.py 
	ZopeDatabaseAdapter.py 
Added Files:
	DatabaseException.py ISQLCommand.py SQLCommand.py 
	configure.zcml 
Log Message:
Finished the initial implementation of the RDB package. The only thing left
is the TypeInfoConverter, which I have not yet attacked.


=== Added File Zope3/lib/python/Zope/App/RDB/DatabaseException.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""
$Id: DatabaseException.py,v 1.1 2002/07/10 23:37:26 srichter Exp $
"""


class DatabaseException(Exception):
    """Generic Database Error"""

    def __init__(self, message):
        self.message = message

    def __str__(self):
        return self.message



=== Added File Zope3/lib/python/Zope/App/RDB/ISQLCommand.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""
$Id: ISQLCommand.py,v 1.1 2002/07/10 23:37:26 srichter Exp $
"""
from Interface import Interface
from Interface.Attribute import Attribute

class ISQLCommand(Interface):
    """Static SQL commands."""
    
    connectionName = Attribute("""The name of the database connection
    to use in getConnection """)

    def getConnection():
        """Get the database connection."""

    def __call__():
        """Execute an sql query and return a result object if appropriate"""

        
__doc__ = ISQLCommand.__doc__








=== Added File Zope3/lib/python/Zope/App/RDB/SQLCommand.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""
$Id: SQLCommand.py,v 1.1 2002/07/10 23:37:26 srichter Exp $
"""
from Zope.ComponentArchitecture import getNextService

from ISQLCommand import ISQLCommand
from Util import queryForResults


class SQLCommand:
    """A simple version of a SQL Command."""

    __implements__ = ISQLCommand

    def __init__(self, connection_name='', sql=''):
        self.connectionName = connection_name
        self.sql = sql

    ############################################################
    # Implementation methods for interface
    # Zope.App.RDB.ISQLCommand.

    def getConnection(self):
        'See Zope.App.RDB.ISQLCommand.ISQLCommand'
        connection_service = getNextService(self, "ConnectionService")
        connection = connection_service.getConnection(self.connectionName)
        return connection

    def __call__(self):
        return queryForResults(self.getConnection(), self.sql)

    #
    ############################################################


=== Added File Zope3/lib/python/Zope/App/RDB/configure.zcml ===
<zopeConfigure
     xmlns='http://namespaces.zope.org/zope'>

<serviceType id="ConnectionService" interface=".IConnectionService." />

<content class=".ResultSet.">
  <require
      permission="Zope.ManageContent"
      interface=".IResultSet." />
</content>

<content class=".Row.">
  <require
      permission="Zope.ManageContent"
      attributes="__getattr__" />
</content>

</zopeConfigure>


=== Zope3/lib/python/Zope/App/RDB/IConnectionService.py 1.2 => 1.3 ===
 # 
 ##############################################################################
 """
-
-Revision information:
 $Id$
 """
 from Interface import Interface, Attribute


=== Zope3/lib/python/Zope/App/RDB/ICursor.py 1.1 => 1.2 ===
 # 
 ##############################################################################
 """
-Revision information:
 $Id$
 """
 
 from Interface import Interface, Attribute
 
 class ICursor(Interface):
+    """DB API ICursor interface"""
 
-    """
-    DB API ICursor interface
-    """
-
-    description = Attribute("""This read-only attribute is a sequence of 7-item sequences. Each of
-        these sequences contains information describing one result column:
-        (name, type_code, display_size, internal_size, precision, scale,
-        null_ok). This attribute will be None for operations that do not
-        return rows or if the cursor has not had an operation invoked via the
-        executeXXX() method yet.
+    description = Attribute("""This read-only attribute is a sequence of
+        7-item sequences. Each of these sequences contains information
+        describing one result column: (name, type_code, display_size,
+        internal_size, precision, scale, null_ok). This attribute will be None
+        for operations that do not return rows or if the cursor has not had an
+        operation invoked via the executeXXX() method yet.
 
         The type_code can be interpreted by comparing it to the Type Objects
         specified in the section below. """)
@@ -94,17 +90,17 @@
         """
         
     def fetchone():
-        """Fetch the next row of a query result set, returning a single sequence,
-        or None when no more data is available. [6]
+        """Fetch the next row of a query result set, returning a single
+        sequence, or None when no more data is available. [6]
 
         An Error (or subclass) exception is raised if the previous call to
         executeXXX() did not produce any result set or no call was issued yet.
         """
 
     def fetchmany(size=ICursor.arraysize):
-        """Fetch the next set of rows of a query result, returning a sequence of
-        sequences (e.g. a list of tuples). An empty sequence is returned when
-        no more rows are available.
+        """Fetch the next set of rows of a query result, returning a sequence
+        of sequences (e.g. a list of tuples). An empty sequence is returned
+        when no more rows are available.
 
         The number of rows to fetch per call is specified by the parameter. If
         it is not given, the cursor's arraysize determines the number of rows
@@ -123,8 +119,7 @@
         """
 
     def fetchall():
-        """
-        Fetch all (remaining) rows of a query result, returning them as a
+        """Fetch all (remaining) rows of a query result, returning them as a
         sequence of sequences (e.g. a list of tuples). Note that the cursor's
         arraysize attribute can affect the performance of this operation.
 


=== Zope3/lib/python/Zope/App/RDB/IDBIConnection.py 1.2 => 1.3 ===
 # 
 ##############################################################################
 """
-
-Revision information:
 $Id$
 """
-
 from Interface import Interface
 
 class IDBIConnection(Interface):


=== Zope3/lib/python/Zope/App/RDB/IDBICursor.py 1.2 => 1.3 ===
 # 
 ##############################################################################
 """
-Revision information:
 $Id$
 """
-
 from Interface import Interface
 from Interface.Attribute import Attribute
 
-arraysize=1 # default constant, symbolic
+arraysize = 1 # default constant, symbolic
 
 class IDBICursor(Interface):
     """DB API ICursor interface"""
 
-    description = Attribute("""This read-only attribute is a sequence of 7-item sequences. Each of
-        these sequences contains information describing one result column:
-        (name, type_code, display_size, internal_size, precision, scale,
-        null_ok). This attribute will be None for operations that do not
-        return rows or if the cursor has not had an operation invoked via the
-        executeXXX() method yet.
+    description = Attribute("""This read-only attribute is a sequence of
+        7-item sequences. Each of these sequences contains information
+        describing one result column: (name, type_code, display_size,
+        internal_size, precision, scale, null_ok). This attribute will be None
+        for operations that do not return rows or if the cursor has not had an
+        operation invoked via the executeXXX() method yet.
 
         The type_code can be interpreted by comparing it to the Type Objects
         specified in the section below. """)
@@ -94,17 +92,17 @@
         """
         
     def fetchone():
-        """Fetch the next row of a query result set, returning a single sequence,
-        or None when no more data is available. [6]
+        """Fetch the next row of a query result set, returning a single
+        sequence, or None when no more data is available. [6]
 
         An Error (or subclass) exception is raised if the previous call to
         executeXXX() did not produce any result set or no call was issued yet.
         """
 
     def fetchmany(size=arraysize):
-        """Fetch the next set of rows of a query result, returning a sequence of
-        sequences (e.g. a list of tuples). An empty sequence is returned when
-        no more rows are available.
+        """Fetch the next set of rows of a query result, returning a sequence
+        of sequences (e.g. a list of tuples). An empty sequence is returned
+        when no more rows are available.
 
         The number of rows to fetch per call is specified by the parameter. If
         it is not given, the cursor's arraysize determines the number of rows
@@ -123,12 +121,10 @@
         """
 
     def fetchall():
-        """
-        Fetch all (remaining) rows of a query result, returning them as a
+        """ Fetch all (remaining) rows of a query result, returning them as a
         sequence of sequences (e.g. a list of tuples). Note that the cursor's
         arraysize attribute can affect the performance of this operation.
 
         An Error (or subclass) exception is raised if the previous call to
         executeXXX() did not produce any result set or no call was issued yet.
         """
-        


=== Zope3/lib/python/Zope/App/RDB/IDBITypeInfo.py 1.1 => 1.2 ===
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+"""
+$Id$
+"""
 from Interface import Interface, Attribute
+
 class IDBITypeInfo(Interface):
-    """
-    Database adapter specific information
-    """
+    """Database adapter specific information"""
+    
     paramstyle = Attribute("""
         String constant stating the type of parameter marker formatting
         expected by the interface. Possible values are [2]:
@@ -25,22 +41,18 @@
 
         Sharing in the above context means that two threads may use a resource
         without wrapping it using a mutex semaphore to implement resource
-        locking. Note that you cannot always make external resources thread safe
-        by managing access using a mutex: the resource may rely on global
+        locking. Note that you cannot always make external resources thread
+        safe by managing access using a mutex: the resource may rely on global
         variables or other external sources that are beyond your control.
         """)
 
     def getConverter():
-        """
-        Return the field type converter.
-        """
+        """Return the field type converter."""
+
 
 class IFieldTypeConverter(Interface):
-    """
-    
-    """
+    """Helper object to convert the low-level database output to a meaningful
+    type."""
 
     def __getitem__(key):
-        """
-        return a converter function for field type matching key
-        """
+        """Return a converter function for field type matching key"""


=== Zope3/lib/python/Zope/App/RDB/IDBITypeInfoProvider.py 1.1 => 1.2 ===
 # FOR A PARTICULAR PURPOSE.
 # 
 ##############################################################################
-"""XXX short summary goes here.
-
-XXX longer description goes here.
+"""
 
 $Id$
 """
-
 from Interface import Interface
 
 class IDBITypeInfoProvider(Interface):
+    """This object can get the Type Info for a particular DBI
+    implementation."""
 
     def getTypeInfo():
-        """return an ITypeInfo object"""
+        """Return an IDBITypeInfo object."""


=== Zope3/lib/python/Zope/App/RDB/IResultSet.py 1.3 => 1.4 ===
 # FOR A PARTICULAR PURPOSE.
 # 
 ##############################################################################
-"""XXX short summary goes here.
-
-XXX longer description goes here.
-
+"""
 $Id$
 """
-
-
 from Interface import Interface
+from Interface.Attribute import Attribute
+
 
 class IResultSet(Interface):
-    """ holds results, and allows iteration """
+    """Holds results, and allows iteration."""
+
+    names = Attribute("""A list of the column names of the returned result
+                      set.""")
 
     def __getitem__(index):
-        "return a brain row for index"
+        """Return a brain row for index."""
 
 
 


=== Zope3/lib/python/Zope/App/RDB/IZopeConnection.py 1.2 => 1.3 ===
 # 
 ##############################################################################
 """
-
-Revision information:
 $Id$
 """
-
 from IDBIConnection import IDBIConnection
 from IDBITypeInfoProvider import IDBITypeInfoProvider
 
 
-class IZopeConnection(IDBIConnection,  IDBITypeInfoProvider):
+class IZopeConnection(IDBIConnection, IDBITypeInfoProvider):
+    """An implementation of this object will be exposed to the user. Therefore
+    the Zope connection represents a conenction in the Zope sense, meaning
+    that the object might not be actually connected to a database.
+    """
 
     def cursor():
         """Return an IZopeCursor object"""
@@ -37,7 +38,7 @@
         """Unregister the connection from the Zope transaction.
 
         This method should only be inovoked by the Zope/DB transaction
-        manager!!!."""
+        manager!!!"""
 
 
         


=== Zope3/lib/python/Zope/App/RDB/IZopeCursor.py 1.2 => 1.3 ===
 # FOR A PARTICULAR PURPOSE.
 # 
 ##############################################################################
-"""XXX short summary goes here.
-
-XXX longer description goes here.
-
+"""
 $Id$
 """
-
 from IDBICursor import IDBICursor
 
 class IZopeCursor(IDBICursor):
-
     """An ICursor that integrates with Zope's transactions"""
 
     def execute(operation, parameters=None):


=== Zope3/lib/python/Zope/App/RDB/IZopeDatabaseAdapter.py 1.2 => 1.3 ===
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+# 
+##############################################################################
+"""
+$Id$
+"""
 from Interface import Interface
 
 class IZopeDatabaseAdapter(Interface):
-    """ interface for persistent object that returns
-    volatile IConnections.
+    """Interface for persistent object that returns
+    volatile IZopeConnections.
 
     This object is internal to the connection service."""
 
+    def setDSN(dsn):
+        """Set the DSN for the Adapter instance"""
+
+    def getDSN(dsn):
+        """Get the DSN of the Adapter instance"""
+
+    def connect():
+        """Connect to the specified database."""
+
+    def disconnect():
+        """Disconnect from the database."""
+
+    def isConnected():
+        """Check whether the Zope Connection is actually connected to the
+        database."""
+
     def __call__():
-        """return an IZopeConnection object"""
+        """Return an IZopeConnection object"""
 


=== Zope3/lib/python/Zope/App/RDB/ResultSet.py 1.2 => 1.3 ===
 # FOR A PARTICULAR PURPOSE.
 # 
 ##############################################################################
-"""XXX short summary goes here.
-
-XXX longer description goes here.
-
+"""
 $Id$
 """
+from Zope.App.RDB.IResultSet import IResultSet
  
 class ResultSet(list):    
-    """
-    Database Result Set. 
+    """Database Result Set. 
 
-    currently we don't do lazy instantation of rows.
+    Currently we don't do lazy instantation of rows.
     """
-    
+
+    __implements__ = IResultSet
     __slots__ = ('names', 'row_klass')
     
     def __init__(self, names, data, row_klass):


=== Zope3/lib/python/Zope/App/RDB/Row.py 1.2 => 1.3 ===
 # FOR A PARTICULAR PURPOSE.
 # 
 ##############################################################################
-"""XXX short summary goes here.
-
-XXX longer description goes here.
-
+"""
 $Id$
 """
 from Zope.Security import Checker
 
-class row(object):
-
+class Row(object):
+    """Represents a row in a ResultSet"""
+    
     def __init__(self, data):
         for k, v in zip(self.__slots__, data):
             setattr(self, k, v)
 
     def __str__(self):
         return "row class %s"%str(self.__slots__)
-            
-def row_class_factory(columns):
 
+            
+def RowClassFactory(columns):
+    """Creates a Row object"""
     klass_namespace = {}
     
-    klass_namespace['__Security_checker__']=Checker.NamesChecker(columns)
-    klass_namespace['__slots__']=tuple(columns)
+    klass_namespace['__Security_checker__'] = Checker.NamesChecker(columns)
+    klass_namespace['__slots__'] = tuple(columns)
 
-    return type('row class', (row,), klass_namespace)
+    return type('row class', (Row,), klass_namespace)
 
 
 


=== Zope3/lib/python/Zope/App/RDB/Util.py 1.2 => 1.3 ===
 # FOR A PARTICULAR PURPOSE.
 # 
 ##############################################################################
-"""XXX short summary goes her
-
-XXX longer description goes here.
-
+"""
 $Id$
 """
+from Zope.App.RDB.DatabaseException import DatabaseException
+from Zope.App.RDB.Row import RowClassFactory
+from Zope.App.RDB.ResultSet import ResultSet
 
-import Row
-import ResultSet
-
-def query_for_results(conn, query):
-
+def queryForResults(conn, query):
+    """Convenience function to quickly execute a query."""
+    
     # need to typing
     cursor = conn.cursor()
-    cursor.execute(query)
+
+    try:
+        cursor.execute(query)
+    except Exception, error:
+        raise DatabaseException(str(error))
 
     columns = [c[0] for c in cursor.description]
 
-    row_klass = Row.row_class_factory(columns)
+    row_klass = RowClassFactory(columns)
     
-    return ResultSet(columns,
-                     cursor.fetchall(),
-                     row_klass)
+    return ResultSet(columns, cursor.fetchall(), row_klass)
+
+
+
 
 
 


=== Zope3/lib/python/Zope/App/RDB/ZopeConnection.py 1.1 => 1.2 ===
 from ZopeDBTransactionManager import ZopeDBTransactionManager
 from Transaction import get_transaction
 
+
 class ZopeConnection:
 
-    __implements__ = IZopeConnection
+    __implements__ =  IZopeConnection
 
     def __init__(self, conn):
         self.conn = conn
         # flag for txn registration status
         self._txn_registered = 0
 
+    def __getattr__(self, key):
+        # The IDBIConnection interface is hereby implemented
+        return self.__dict__.get(key, getattr(self.conn, key))
+
+    ############################################################
+    # Implementation methods for interface
+    # Zope/App/RDB/IZopeConnection.py
+
     def cursor(self):
-        """Returns an IZopeCursor"""
+        'See Zope.App.RDB.IZopeConnection.IZopeConnection'
         return ZopeCursor(self.conn.cursor(), self)
 
     def registerForTxn(self):
-        
-        if self._txn_registered:
-            return
+        'See Zope.App.RDB.IZopeConnection.IZopeConnection'
+        if not self._txn_registered:
+            tm = ZopeDBTransactionManager(self)
+            t = get_transaction()
+            t.register(tm)
+            self._txn_registered = 1
 
-        tm = ZopeDBTransactionManager(self)
-        t = get_transaction()
-        t.register(tm)
-        self._txn_registered = 1
-        
     def unregisterFromTxn(self):
+        'See Zope.App.RDB.IZopeConnection.IZopeConnection'
         self._txn_registered = 0
-        
-    def __getattr__(self, key):
-        return getattr(self.conn, key)
+
+    ######################################
+    # from: Zope.App.RDB.IDBITypeInfoProvider.IDBITypeInfoProvider
 
     def getTypeInfo(self):
+        'See Zope.App.RDB.IDBITypeInfoProvider.IDBITypeInfoProvider'
         # Stubbed for now
-        pass
-
-
-
-
+        
+    #
+    ############################################################


=== Zope3/lib/python/Zope/App/RDB/ZopeCursor.py 1.1 => 1.2 ===
 """
 $Id$
 """
+from types import UnicodeType
 from IZopeCursor import IZopeCursor
 
 class ZopeCursor:
@@ -27,6 +28,10 @@
         """Executes an operation, registering the underlying
         connection with the transaction system.  """
 
+        if isinstance(operation, UnicodeType):
+            operation = operation.encode('UTF-8')
+        if parameters is None:
+            parameters = {}
         self.connection.registerForTxn()
         return self.cursor.execute(operation, parameters)
 


=== Zope3/lib/python/Zope/App/RDB/ZopeDBTransactionManager.py 1.1 => 1.2 ===
 
 $Id$
 """
-
 from Transaction.IDataManager import IDataManager
 
 class ZopeDBTransactionManager:
 
     __implements__ =  IDataManager
 
-    ############################################################
-    # Implementation methods for interface
-    # IDataManager.py
-    ###
-    # Subtransactions methods moved.
-    #
-
     def __init__(self, dbconn):
-        """
-        callback is a function invoked when the
-        transaction is finished.
+        """Callback is a function invoked when the transaction is finished.
         """
         self.dbconn = dbconn
         self._vote = 0
 
+    ############################################################
+    # Implementation methods for interface
+    # Zope.Transaction.IDataManager.
+
     def abort(self, *ignored):
         'See Transaction.IDataManager.IDataManager'
-        try: self.dbconn.rollback()
-        finally: self.dbconn.unregisterFromTxn()
+        try:
+            self.dbconn.rollback()
+        finally:
+            self.dbconn.unregisterFromTxn()
+
+    def commit(self, *ignored):
+        'See Transaction.IDataManager.IDataManager'
 
     def tpc_vote(self, *ignored):
         'See Transaction.IDataManager.IDataManager'
         self._vote = 1
         
+    def tpc_begin(self, *ignored):
+        'See Transaction.IDataManager.IDataManager'
+
     def tpc_finish(self, *ignored):
         'See Transaction.IDataManager.IDataManager'
         if self._vote:
-            try: self.dbconn.commit()
-            finally: self.dbconn.unregisterFromTxn()
+            try:
+                self.dbconn.commit()
+            finally:
+                self.dbconn.unregisterFromTxn()
         
     tpc_abort = abort
-
-    def tpc_begin(self, *ignored):
-        'See Transaction.IDataManager.IDataManager'
-        
-    def commit(self, *ignored):
-        'See Transaction.IDataManager.IDataManager'
     
     #
     ############################################################


=== Zope3/lib/python/Zope/App/RDB/ZopeDatabaseAdapter.py 1.2 => 1.3 ===
 
 $Id$
 """
-
-from Zope.Configuration.name import resolve
+from types import StringTypes
 from Persistence import Persistent
 from Zope.App.RDB.IZopeDatabaseAdapter import IZopeDatabaseAdapter
+from Zope.App.RDB.ZopeConnection import ZopeConnection
+
 class ZopeDatabaseAdapter(Persistent):
 
     __implements__ = IZopeDatabaseAdapter
     _v_connection =  None
 
-    def __init__(self, id, title, factory, user, password, host, database):
-        self.id       = id
-        self.title    = title
-        self.factory  = factory
-        self.user     = user
-        self.password = password
-        self.host     = host
-        self.database = database
+    def __init__(self, dsn):
+        self.setDSN(dsn)
         
+    def _connection_factory(self):
+        """This method should be overwritten by all subclasses"""
+        conn_info = _parseDSN(self.dsn)
+        
+    ############################################################
+    # Implementation methods for interface
+    # Zope.App.RDB.IZopeDatabaseAdapter.
+
+    def setDSN(self, dsn):
+        'See Zope.App.RDB.IZopeDatabaseAdapter.IZopeDatabaseAdapter'
+        assert dsn.startswith('dbi://'), "The DSN has to start with 'dbi://'"
+        self.dsn = dsn
+
+    def getDSN(self):
+        'See Zope.App.RDB.IZopeDatabaseAdapter.IZopeDatabaseAdapter'
+        return self.dsn
+
+    def connect(self):
+        'See Zope.App.RDB.IZopeDatabaseAdapter.IZopeDatabaseAdapter'
+        if not self.isConnected():
+            self._v_connection = ZopeConnection(self._connection_factory())
+
+    def disconnect(self):
+        'See Zope.App.RDB.IZopeDatabaseAdapter.IZopeDatabaseAdapter'
+        if self.isConnected():
+           self._v_connection.close()
+           self._v_connection = None
+
+    def isConnected(self):
+        'See Zope.App.RDB.IZopeDatabaseAdapter.IZopeDatabaseAdapter'
+        return hasattr(self, '_v_connection') and \
+               self._v_connection is not None
+
     def __call__(self):
+        'See Zope.App.RDB.IZopeDatabaseAdapter.IZopeDatabaseAdapter'
+        self.connect()
+        return self._v_connection
 
-        if self._v_connection is not None:
-            return self._v_connection
+    #
+    ############################################################
 
-        factory = resolve(self.factory)
-        self._v_connection = factory(user=self.user,
-                                     password=self.password,
-                                     host=self.host,
-                                     database=self.database)
-        return self._v_connection
 
 
+def parseDSN(dsn):
+    """We could have the following cases:
+
+       dbi://dbname
+       dbi://dbname;param1=value...
+       dbi://user:passwd/dbname
+       dbi://user:passwd/dbname;param1=value...
+       dbi://user:passwd@host:port/dbname
+       dbi://user:passwd@host:port/dbname;param1=value...
+    """
+    assert isinstance(dsn, StringTypes), 'The dsn is not a string.'
+    assert dsn.startswith('dbi://'), 'Invalid DSN; must start with "dbi://"'
+
+    result = {}
+
+    dsn = dsn[6:]
+    # Get parameters (dict) from DSN
+    raw_params = dsn.split(';')
+    dsn = raw_params[0]
+    raw_params = raw_params[1:]
+
+    parameters = {}
+    for string in raw_params:
+        param, value = string.split('=')
+        parameters[param] = value
+
+    result['parameters'] = parameters
+
+    # Get the dbname from the DSN
+    if dsn.find('/') > 0:
+        dsn, dbname = dsn.split('/')
+    else:
+        dbname = dsn
+        dsn = ''
+
+    result['dbname'] = dbname
+
+    # Get host and port from DSN
+    if dsn and dsn.find('@') > 0:
+        dsn, host_port = dsn.split('@')
+        host, port = host_port.split(':')
+    else:
+        host, port = '', ''
+
+    result['host'] = host
+    result['port'] = port
+    
+    # Get username and password from DSN
+    if dsn:
+        username, password = dsn.split(':')
+    else:
+        username, password = '', ''
+
+    result['username'] = username
+    result['password'] = password
 
+    return result