[CalendarServer-changes] [5926] CalendarServer/branches/new-store-no-caldavfile

source_changes at macosforge.org source_changes at macosforge.org
Fri Jul 23 10:06:53 PDT 2010


Revision: 5926
          http://trac.macosforge.org/projects/calendarserver/changeset/5926
Author:   cdaboo at apple.com
Date:     2010-07-23 10:06:51 -0700 (Fri, 23 Jul 2010)
Log Message:
-----------
Remove twistedcaldav.static.py! Currently passes all CDT tests. Unit tests still broken. Tools
broken. Much more clean-up, re-factoring required.

Modified Paths:
--------------
    CalendarServer/branches/new-store-no-caldavfile/calendarserver/provision/root.py
    CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/util.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/acl.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/copymove.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/delete.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/delete_common.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/get.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/mkcol.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/propfind.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/proppatch.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/put.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/report.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/resource.py
    CalendarServer/branches/new-store-no-caldavfile/twext/web2/server.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/bind.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/addressbook.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendar.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/opendirectorybacker.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directorybackedaddressbook.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/extensions.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/index.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/mail.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/__init__.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/acl.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/copymove.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/copymove_contact.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/get.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/mkcol.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_addressbook_common.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_common.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_addressbook_query.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_calendar_query.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_common.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_freebusy.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notifications.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/resource.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/schedule.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/caldav.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/processing.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharedcollection.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharing.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/simpleresource.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/storebridge.py
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/vcardindex.py
    CalendarServer/branches/new-store-no-caldavfile/txcaldav/calendarstore/file.py
    CalendarServer/branches/new-store-no-caldavfile/txcarddav/addressbookstore/file.py
    CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/file.py

Removed Paths:
-------------
    CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/static.py

Modified: CalendarServer/branches/new-store-no-caldavfile/calendarserver/provision/root.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/calendarserver/provision/root.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/calendarserver/provision/root.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -19,20 +19,20 @@
     "RootResource",
 ]
 
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twext.python.log import Logger
 from twext.web2 import responsecode
+from twext.web2.auth.wrapper import UnauthorizedResponse
 from twext.web2.dav import davxml
 from twext.web2.http import HTTPError, StatusResponse
-from twext.web2.auth.wrapper import UnauthorizedResponse
+
+from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.web.xmlrpc import Proxy
 
-from twext.python.log import Logger
-
-from twistedcaldav.resource import CalDAVComplianceMixIn
+from twistedcaldav.config import config
 from twistedcaldav.extensions import DAVFile, CachingPropertyStore
 from twistedcaldav.extensions import DirectoryPrincipalPropertySearchMixIn
 from twistedcaldav.extensions import ReadOnlyResourceMixIn
-from twistedcaldav.config import config
+from twistedcaldav.resource import CalDAVComplianceMixIn
 
 log = Logger()
 
@@ -69,7 +69,6 @@
             self.contentFilters.append((addConnectionClose, True))
 
     def deadProperties(self):
-        # FIXME: Same as in static.py's CalDAVFile
         if not hasattr(self, "_dead_properties"):
             # Get the property store from super
             deadProperties = super(RootResource, self).deadProperties()

Modified: CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/util.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/util.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/calendarserver/tap/util.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -23,17 +23,18 @@
 import os
 from time import sleep
 
-from twisted.python.reflect import namedClass
-from twisted.internet.reactor import addSystemEventTrigger
-from twisted.cred.portal import Portal
-from twext.web2.http_headers import Headers
-from twext.web2.dav import auth
+from twext.python.filepath import CachingFilePath as FilePath
+from twext.python.log import Logger
 from twext.web2.auth.basic import BasicCredentialFactory
+from twext.web2.dav import auth
+from twext.web2.http_headers import Headers
 from twext.web2.resource import RedirectResource
 from twext.web2.static import File as FileResource
-from twext.python.filepath import CachingFilePath as FilePath
 
-from twext.python.log import Logger
+from twisted.cred.portal import Portal
+from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.reactor import addSystemEventTrigger
+from twisted.python.reflect import namedClass
 
 from twistedcaldav import memcachepool
 from twistedcaldav.bind import doBind
@@ -47,15 +48,14 @@
 from twistedcaldav.directory.sudo import SudoDirectoryService
 from twistedcaldav.directory.util import NotFilePath
 from twistedcaldav.directory.wiki import WikiDirectoryService
+from twistedcaldav.directorybackedaddressbook import DirectoryBackedAddressBookResource
 from twistedcaldav.notify import installNotificationClient
 from twistedcaldav.resource import CalDAVResource, AuthenticationWrapper
 from twistedcaldav.schedule import IScheduleInboxResource
 from twistedcaldav.simpleresource import SimpleResource
-from twistedcaldav.static import DirectoryBackedAddressBookFile
 from twistedcaldav.timezones import TimezoneCache
 from twistedcaldav.timezoneservice import TimezoneServiceResource
 from twistedcaldav.util import getMemorySize, getNCPU
-from twisted.internet.defer import inlineCallbacks, returnValue
 
 try:
     from twistedcaldav.authkerb import NegotiateCredentialFactory
@@ -98,7 +98,7 @@
     webCalendarResourceClass     = WebCalendarResource
     webAdminResourceClass        = WebAdminResource
     addressBookResourceClass     = DirectoryAddressBookHomeProvisioningResource
-    directoryBackedAddressBookResourceClass = DirectoryBackedAddressBookFile
+    directoryBackedAddressBookResourceClass = DirectoryBackedAddressBookResource
 
     #
     # Setup the Directory
@@ -309,7 +309,6 @@
             log.info("Setting up directory address book: %r" % (directoryBackedAddressBookResourceClass,))
 
             directoryBackedAddressBookCollection = directoryBackedAddressBookResourceClass(
-                directoryPath,
                 principalCollections=(principalCollection,)
             )
             addSystemEventTrigger("after", "startup", directoryBackedAddressBookCollection.provisionDirectory)

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/acl.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/acl.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/acl.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -45,8 +45,8 @@
     """
     Respond to a ACL request. (RFC 3744, section 8.1)
     """
-    if not self.fp.exists():
-        log.err("File not found: %s" % (self.fp.path,))
+    if not self.exists():
+        log.err("File not found: %s" % (self,))
         yield responsecode.NOT_FOUND
         return
 

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/copymove.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/copymove.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/copymove.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -152,7 +152,7 @@
     #
     # Let's play it safe for now and ignore broken clients.
     #
-    if self.fp.isdir() and depth != "infinity":
+    if self.isCollection() and depth != "infinity":
         msg = "Client sent illegal depth header value for MOVE: %s" % (depth,)
         log.err(msg)
         raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, msg))
@@ -192,7 +192,7 @@
     #
 
     if not self.exists():
-        log.err("File not found: %s" % (self.fp.path,))
+        log.err("File not found: %s" % (self,))
         raise HTTPError(StatusResponse(
             responsecode.NOT_FOUND,
             "Source resource %s not found." % (request.uri,)
@@ -250,7 +250,7 @@
 
     if destination.exists() and not overwrite:
         log.err("Attempt to %s onto existing file without overwrite flag enabled: %s"
-                % (request.method, destination.fp.path))
+                % (request.method, destination))
         raise HTTPError(StatusResponse(
             responsecode.PRECONDITION_FAILED,
             "Destination %s already exists." % (destination_uri,)
@@ -260,9 +260,9 @@
     # Make sure destination's parent exists
     #
 
-    if not destination.fp.parent().isdir():
+    if not destination.parent().isCollection():
         log.err("Attempt to %s to a resource with no parent: %s"
-                % (request.method, destination.fp.path))
+                % (request.method, destination))
         raise HTTPError(StatusResponse(responsecode.CONFLICT, "No parent collection."))
 
     return destination, destination_uri, depth

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/delete.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/delete.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/delete.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -45,8 +45,8 @@
     """
     Respond to a DELETE request. (RFC 2518, section 8.6)
     """
-    if not self.fp.exists():
-        log.err("File not found: %s" % (self.fp.path,))
+    if not self.exists():
+        log.err("File not found: %s" % (self,))
         raise HTTPError(responsecode.NOT_FOUND)
 
     depth = request.headers.getHeader("depth", "infinity")

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/delete_common.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/delete_common.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/delete_common.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -41,8 +41,8 @@
     """
     Handle a resource delete with proper quota etc updates
     """
-    if not resource.fp.exists():
-        log.err("File not found: %s" % (resource.fp.path,))
+    if not resource.exists():
+        log.err("File not found: %s" % (resource,))
         raise HTTPError(responsecode.NOT_FOUND)
 
     # Do quota checks before we start deleting things

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/get.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/get.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/get.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -36,17 +36,17 @@
 
 def http_OPTIONS(self, request):
     d = authorize(self, request)
-    d.addCallback(lambda _: super(twext.web2.dav.static.DAVFile, self).http_OPTIONS(request))
+    d.addCallback(lambda _: super(twext.web2.dav.resource.DAVResource, self).http_OPTIONS(request))
     return d
 
 def http_HEAD(self, request):
     d = authorize(self, request)
-    d.addCallback(lambda _: super(twext.web2.dav.static.DAVFile, self).http_HEAD(request))
+    d.addCallback(lambda _: super(twext.web2.dav.resource.DAVResource, self).http_HEAD(request))
     return d
 
 def http_GET(self, request):
     d = authorize(self, request)
-    d.addCallback(lambda _: super(twext.web2.dav.static.DAVFile, self).http_GET(request))
+    d.addCallback(lambda _: super(twext.web2.dav.resource.DAVResource, self).http_GET(request))
     return d
 
 def authorize(self, request):

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/mkcol.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/mkcol.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/mkcol.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -53,14 +53,14 @@
     yield x
     x.getResult()
 
-    if self.fp.exists():
+    if self.exists():
         log.err("Attempt to create collection where file exists: %s"
-                % (self.fp.path,))
+                % (self,))
         raise HTTPError(responsecode.NOT_ALLOWED)
 
     if not parent.isCollection():
         log.err("Attempt to create collection with non-collection parent: %s"
-                % (self.fp.path,))
+                % (self,))
         raise HTTPError(StatusResponse(
             responsecode.CONFLICT,
             "Parent resource is not a collection."

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/propfind.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/propfind.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/propfind.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -51,7 +51,7 @@
     Respond to a PROPFIND request. (RFC 2518, section 8.1)
     """
     if not self.exists():
-        log.err("File not found: %s" % (self.fp.path,))
+        log.err("File not found: %s" % (self,))
         raise HTTPError(responsecode.NOT_FOUND)
 
     #

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/proppatch.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/proppatch.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/proppatch.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -46,8 +46,8 @@
     """
     Respond to a PROPPATCH request. (RFC 2518, section 8.2)
     """
-    if not self.fp.exists():
-        log.err("File not found: %s" % (self.fp.path,))
+    if not self.exists():
+        log.err("File not found: %s" % (self.path,))
         raise HTTPError(responsecode.NOT_FOUND)
 
     x = waitForDeferred(self.authorize(request, (davxml.WriteProperties(),)))

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/put.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/put.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/put.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -88,7 +88,7 @@
     """
     Respond to a PUT request. (RFC 2518, section 8.7)
     """
-    log.msg("Writing request stream to %s" % (self.fp.path,))
+    log.msg("Writing request stream to %s" % (self,))
 
     #
     # Don't pass in the request URI, since PUT isn't specified to be able

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/report.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/report.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/method/report.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -64,8 +64,8 @@
     """
     Respond to a REPORT request. (RFC 3253, section 3.6)
     """
-    if not self.fp.exists():
-        log.err("File not found: %s" % (self.fp.path,))
+    if not self.exists():
+        log.err("File not found: %s" % (self,))
         raise HTTPError(responsecode.NOT_FOUND)
 
     #

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/resource.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/resource.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/dav/resource.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -1356,7 +1356,7 @@
         This implementation returns a supported privilege set
         containing only the DAV:all privilege.
         """
-        return succeed(allPrivilegeSet)
+        return succeed(davPrivilegeSet)
 
     def currentPrivileges(self, request):
         """

Modified: CalendarServer/branches/new-store-no-caldavfile/twext/web2/server.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twext/web2/server.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twext/web2/server.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -445,6 +445,13 @@
         self._urlsByResource[resource] = url
         return resource
 
+    def _forgetResource(self, resource, url):
+        """
+        Remember the URL of a visited resource.
+        """
+        del self._resourcesByURL[url]
+        del self._urlsByResource[resource]
+
     def urlForResource(self, resource):
         """
         Looks up the URL of the given resource if this resource was found while

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/bind.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/bind.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/bind.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -26,6 +26,10 @@
 ##
 
 def doBind():
+    import twext.web2.dav.method
+    from twext.web2.dav.resource import DAVResource
+    bindMethods(twext.web2.dav.method, DAVResource)
+
     import twistedcaldav.method
     from twistedcaldav.resource import CalDAVResource
     bindMethods(twistedcaldav.method, CalDAVResource)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/addressbook.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/addressbook.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/addressbook.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -33,6 +33,7 @@
 from twext.web2.dav.resource import TwistedACLInheritable
 from twext.web2.dav.util import joinURL
 from twext.web2.http import HTTPError
+from twext.web2.http_headers import ETag, MimeType
 
 from twisted.internet.defer import succeed
 
@@ -43,6 +44,8 @@
 from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource,\
     DAVResourceWithChildrenMixin
 
+from uuid import uuid4
+
 log = Logger()
 
 # Use __underbars__ convention to avoid conflicts with directory resource types.
@@ -60,13 +63,19 @@
     AutoProvisioningResourceMixIn,
     ReadOnlyResourceMixIn,
     CalDAVComplianceMixIn,
+    DAVResourceWithChildrenMixin,
     DAVResource,
-    DAVResourceWithChildrenMixin,
 ):
     def defaultAccessControlList(self):
         return config.ProvisioningResourceACL
 
+    def etag(self):
+        return ETag(str(uuid4()))
 
+    def contentType(self):
+        return MimeType("httpd", "unix-directory")
+
+
 class DirectoryAddressBookHomeProvisioningResource (DirectoryAddressBookProvisioningResource):
     """
     Resource which provisions address book home collections as needed.    
@@ -79,8 +88,7 @@
         assert directory is not None
         assert url.endswith("/"), "Collection URL must end in '/'"
 
-        DAVResource.__init__(self)
-        DAVResourceWithChildrenMixin.__init__(self)
+        super(DirectoryAddressBookHomeProvisioningResource, self).__init__()
 
         self.directory = IDirectoryService(directory)
         self._url = url
@@ -136,7 +144,10 @@
     def isCollection(self):
         return True
 
+    def displayName(self):
+        return "addressbooks"
 
+
 class DirectoryAddressBookHomeTypeProvisioningResource (DirectoryAddressBookProvisioningResource):
     """
     Resource which provisions address book home collections of a specific
@@ -150,8 +161,7 @@
         assert parent is not None
         assert recordType is not None
 
-        DAVResource.__init__(self)
-        DAVResourceWithChildrenMixin.__init__(self)
+        super(DirectoryAddressBookHomeTypeProvisioningResource, self).__init__()
 
         self.directory = parent.directory
         self.recordType = recordType
@@ -188,7 +198,7 @@
             raise HTTPError(responsecode.FORBIDDEN)
 
     def makeChild(self, name):
-        raise HTTPError(responsecode.NOT_FOUND)
+        return None
 
     ##
     # DAV
@@ -197,6 +207,9 @@
     def isCollection(self):
         return True
 
+    def displayName(self):
+        return self.recordType
+
     ##
     # ACL
     ##
@@ -216,8 +229,7 @@
         """
         assert parent is not None
 
-        DAVResource.__init__(self)
-        DAVResourceWithChildrenMixin.__init__(self)
+        super(DirectoryAddressBookHomeUIDProvisioningResource, self).__init__()
 
         self.directory = parent.directory
         self.parent = parent
@@ -283,6 +295,9 @@
     def isCollection(self):
         return True
 
+    def displayName(self):
+        return uidsResourceName
+
     ##
     # ACL
     ##
@@ -294,7 +309,7 @@
         return self.parent.principalForRecord(record)
 
 
-class DirectoryAddressBookHomeResource (AutoProvisioningResourceMixIn, DAVResource, DAVResourceWithChildrenMixin):
+class DirectoryAddressBookHomeResource (AutoProvisioningResourceMixIn, DAVResource):
     """
     Address book home collection resource.
     """
@@ -305,8 +320,7 @@
         assert parent is not None
         assert record is not None
 
-        DAVResource.__init__(self)
-        DAVResourceWithChildrenMixin.__init__(self)
+        super(DirectoryAddressBookHomeResource, self).__init__()
 
         self.record = record
         self.parent = parent

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendar.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/calendar.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -28,14 +28,15 @@
     "DirectoryCalendarHomeResource",
 ]
 
-from twisted.internet.defer import succeed
+from twext.python.log import Logger
 from twext.web2 import responsecode
 from twext.web2.dav import davxml
+from twext.web2.dav.resource import TwistedACLInheritable
+from twext.web2.dav.util import joinURL
 from twext.web2.http import HTTPError
-from twext.web2.dav.util import joinURL
-from twext.web2.dav.resource import TwistedACLInheritable
+from twext.web2.http_headers import ETag, MimeType
 
-from twext.python.log import Logger
+from twisted.internet.defer import succeed
 
 from twistedcaldav import caldavxml
 from twistedcaldav.config import config
@@ -47,6 +48,8 @@
 from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn,\
     DirectoryReverseProxyResource
 
+from uuid import uuid4
+
 log = Logger()
 
 # Use __underbars__ convention to avoid conflicts with directory resource types.
@@ -64,13 +67,18 @@
     AutoProvisioningResourceMixIn,
     ReadOnlyResourceMixIn,
     CalDAVComplianceMixIn,
+    DAVResourceWithChildrenMixin,
     DAVResource,
-    DAVResourceWithChildrenMixin,
 ):
     def defaultAccessControlList(self):
         return config.ProvisioningResourceACL
 
+    def etag(self):
+        return ETag(str(uuid4()))
 
+    def contentType(self):
+        return MimeType("httpd", "unix-directory")
+
 class DirectoryCalendarHomeProvisioningResource (DirectoryCalendarProvisioningResource):
     """
     Resource which provisions calendar home collections as needed.    
@@ -83,8 +91,7 @@
         assert directory is not None
         assert url.endswith("/"), "Collection URL must end in '/'"
 
-        DAVResource.__init__(self)
-        DAVResourceWithChildrenMixin.__init__(self)
+        super(DirectoryCalendarHomeProvisioningResource, self).__init__()
 
         self.directory = IDirectoryService(directory)
         self._url = url
@@ -140,6 +147,8 @@
     def isCollection(self):
         return True
 
+    def displayName(self):
+        return "calendars"
 
 class DirectoryCalendarHomeTypeProvisioningResource (DirectoryCalendarProvisioningResource):
     """
@@ -154,8 +163,7 @@
         assert parent is not None
         assert recordType is not None
 
-        DAVResource.__init__(self)
-        DAVResourceWithChildrenMixin.__init__(self)
+        super(DirectoryCalendarHomeTypeProvisioningResource, self).__init__()
 
         self.directory = parent.directory
         self.recordType = recordType
@@ -192,7 +200,7 @@
             raise HTTPError(responsecode.FORBIDDEN)
 
     def makeChild(self, name):
-        raise HTTPError(responsecode.NOT_FOUND)
+        return None
 
     ##
     # DAV
@@ -201,6 +209,9 @@
     def isCollection(self):
         return True
 
+    def displayName(self):
+        return self.recordType
+
     ##
     # ACL
     ##
@@ -211,7 +222,6 @@
     def principalForRecord(self, record):
         return self._parent.principalForRecord(record)
 
-
 class DirectoryCalendarHomeUIDProvisioningResource (DirectoryCalendarProvisioningResource):
 
     def __init__(self, parent):
@@ -220,8 +230,7 @@
         """
         assert parent is not None
 
-        DAVResource.__init__(self)
-        DAVResourceWithChildrenMixin.__init__(self)
+        super(DirectoryCalendarHomeUIDProvisioningResource, self).__init__()
 
         self.directory = parent.directory
         self.parent = parent
@@ -287,6 +296,9 @@
     def isCollection(self):
         return True
 
+    def displayName(self):
+        return uidsResourceName
+
     ##
     # ACL
     ##
@@ -298,7 +310,7 @@
         return self.parent.principalForRecord(record)
 
 
-class DirectoryCalendarHomeResource (AutoProvisioningResourceMixIn, DAVResource, DAVResourceWithChildrenMixin):
+class DirectoryCalendarHomeResource (AutoProvisioningResourceMixIn, DAVResource):
     """
     Calendar home collection resource.
     """
@@ -309,8 +321,7 @@
         assert parent is not None
         assert record is not None
 
-        DAVResource.__init__(self)
-        DAVResourceWithChildrenMixin.__init__(self)
+        super(DirectoryCalendarHomeResource, self).__init__()
 
         self.record = record
         self.parent = parent

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/opendirectorybacker.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/opendirectorybacker.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directory/opendirectorybacker.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -61,7 +61,6 @@
 from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
 from twistedcaldav.method.put_addressbook_common import StoreAddressObjectResource
 from twistedcaldav.query import addressbookqueryfilter
-from twistedcaldav.static import CalDAVFile
 from twistedcaldav.vcard import Component, Property
 
 from xmlrpclib import datetime
@@ -398,64 +397,65 @@
                     yield updateLock.release()
                     updateLock = None
                     
-                    tmpDirLock = self._tmpDirAddressBookLock
-                    self.log_debug("blocking on lock of: \"%s\")" % self._tmpDirAddressBookLockPath)
-                    yield tmpDirLock.acquire()
-                    
-                    try:
-                        self.log_info("Filling directory address book")
-                        startTime = time.time()
-                        newAddressBook = CalDAVFile(makeTmpFilename())
-                        yield newAddressBook.createAddressBookCollection()
-                        for key, record in records.items():
-                            try:
-                                vcard = record.vCard()
-                                # make up a destination 
-
-                                fileName = unquote(record.uriName())
-                                destination = CalDAVFile(join(newAddressBook.fp.path, fileName))
-                                destination_uri =  record.hRef()
-
-                                self.log_debug("Adding \"%s\", uri=\"%s\"" % (fileName, destination_uri, ))
-                                self.log_debug("VCard text =\n%s" % (record.vCardText(), ))
-                                
-                                yield StoreAddressObjectResource( request = None,
-                                                            sourceadbk = False,
-                                                            destinationadbk = True,
-                                                            destination = destination,
-                                                            destination_uri = destination_uri,
-                                                            destinationparent = newAddressBook,
-                                                            vcard = vcard,
-                                                            indexdestination = False,
-                                                            ).run()
-                            except:
-                                self.log_info("Could not add record %s" % (record,))
-                                del records[key]
-                                newAddressBookCTag = customxml.GETCTag(str(hash(self.baseGUID + ":" + self.realmName + ":" + "".join(str(hash(records[key])) for key in records.keys()))))
-                        
-                        self.log_info("Indexing new directory address book")
-                        newAddressBook.index().recreate()
-                        elaspedTime = time.time()-startTime
-                        self.log_info("Timing: Fill address book: %.1f ms (%d vcards, %.2f vcards/sec)" % (elaspedTime*1000, len(records), len(records)/elaspedTime))
-                        
-                        updateLock = self.updateLock()
-                        self.log_debug("blocking on lock of: \"%s\")" % self._updateLockPath)
-                        yield updateLock.acquire()
-
-                        self.log_debug("Swapping in new directory address book")
-                        
-                        # move old address book out of the way
-                        if self.directoryBackedAddressBook.fp.exists():               
-                            os.rename(self.directoryBackedAddressBook.fp.path, makeTmpFilename())
-        
-                        #move new one into place
-                        os.rename(newAddressBook.fp.path, self.directoryBackedAddressBook.fp.path)
-                        self.directoryBackedAddressBook.fp.restat()
-                        
-                        self.directoryBackedAddressBook.writeDeadProperty(newAddressBookCTag)
-                    finally:
-                        self.log_debug("unlocking: \"%s\")" % self._tmpDirAddressBookLockPath)
-                        yield tmpDirLock.release()
+                    #FIXME: implement store based cache
+#                    tmpDirLock = self._tmpDirAddressBookLock
+#                    self.log_debug("blocking on lock of: \"%s\")" % self._tmpDirAddressBookLockPath)
+#                    yield tmpDirLock.acquire()
+#                    
+#                    try:
+#                        self.log_info("Filling directory address book")
+#                        startTime = time.time()
+#                        newAddressBook = CalDAVFile(makeTmpFilename())
+#                        yield newAddressBook.createAddressBookCollection()
+#                        for key, record in records.items():
+#                            try:
+#                                vcard = record.vCard()
+#                                # make up a destination 
+#
+#                                fileName = unquote(record.uriName())
+#                                destination = CalDAVFile(join(newAddressBook.fp.path, fileName))
+#                                destination_uri =  record.hRef()
+#
+#                                self.log_debug("Adding \"%s\", uri=\"%s\"" % (fileName, destination_uri, ))
+#                                self.log_debug("VCard text =\n%s" % (record.vCardText(), ))
+#                                
+#                                yield StoreAddressObjectResource( request = None,
+#                                                            sourceadbk = False,
+#                                                            destinationadbk = True,
+#                                                            destination = destination,
+#                                                            destination_uri = destination_uri,
+#                                                            destinationparent = newAddressBook,
+#                                                            vcard = vcard,
+#                                                            indexdestination = False,
+#                                                            ).run()
+#                            except:
+#                                self.log_info("Could not add record %s" % (record,))
+#                                del records[key]
+#                                newAddressBookCTag = customxml.GETCTag(str(hash(self.baseGUID + ":" + self.realmName + ":" + "".join(str(hash(records[key])) for key in records.keys()))))
+#                        
+#                        self.log_info("Indexing new directory address book")
+#                        newAddressBook.index().recreate()
+#                        elaspedTime = time.time()-startTime
+#                        self.log_info("Timing: Fill address book: %.1f ms (%d vcards, %.2f vcards/sec)" % (elaspedTime*1000, len(records), len(records)/elaspedTime))
+#                        
+#                        updateLock = self.updateLock()
+#                        self.log_debug("blocking on lock of: \"%s\")" % self._updateLockPath)
+#                        yield updateLock.acquire()
+#
+#                        self.log_debug("Swapping in new directory address book")
+#                        
+#                        # move old address book out of the way
+#                        if self.directoryBackedAddressBook.fp.exists():               
+#                            os.rename(self.directoryBackedAddressBook.fp.path, makeTmpFilename())
+#        
+#                        #move new one into place
+#                        os.rename(newAddressBook.fp.path, self.directoryBackedAddressBook.fp.path)
+#                        self.directoryBackedAddressBook.fp.restat()
+#                        
+#                        self.directoryBackedAddressBook.writeDeadProperty(newAddressBookCTag)
+#                    finally:
+#                        self.log_debug("unlocking: \"%s\")" % self._tmpDirAddressBookLockPath)
+#                        yield tmpDirLock.release()
     
                 if not keepLock:
                     self.log_debug("unlocking: \"%s\")" % self._updateLockPath)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directorybackedaddressbook.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directorybackedaddressbook.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/directorybackedaddressbook.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -22,22 +22,18 @@
     "DirectoryBackedAddressBookResource",
 ]
 
-
-
 from twext.python.log import Logger
-from twisted.internet.defer import succeed, inlineCallbacks, maybeDeferred, returnValue
-from twisted.python.reflect import namedClass
 from twext.web2 import responsecode
 from twext.web2.dav import davxml
 from twext.web2.dav.resource import TwistedACLInheritable
 from twext.web2.http import HTTPError, StatusResponse
 
+from twisted.internet.defer import succeed, inlineCallbacks, maybeDeferred, returnValue
+from twisted.python.reflect import namedClass
+
 from twistedcaldav.config import config
 from twistedcaldav.resource import CalDAVResource
 
-
-
-
 log = Logger()
 
 
@@ -47,13 +43,36 @@
     Directory-backed address book
     """
 
-    def __init__(self):
+    def __init__(self, principalCollections):
 
-        CalDAVResource.__init__(self)
+        CalDAVResource.__init__(self, principalCollections=principalCollections)
 
         self.directory = None       # creates directory attribute
 
+        # create with permissions, similar to CardDAVOptions in tap.py
+        # FIXME:  /Directory does not need to be in file system unless debug-only caching options are used
+#        try:
+#            os.mkdir(path)
+#            os.chmod(path, 0750)
+#            if config.UserName and config.GroupName:
+#                import pwd
+#                import grp
+#                uid = pwd.getpwnam(config.UserName)[2]
+#                gid = grp.getgrnam(config.GroupName)[2]
+#                os.chown(path, uid, gid)
+# 
+#            log.msg("Created %s" % (path,))
+#            
+#        except (OSError,), e:
+#            # this is caused by multiprocessor race and is harmless
+#            if e.errno != errno.EEXIST:
+#                raise
+
         
+    def makeChild(self, name):
+        from twistedcaldav.simpleresource import SimpleCalDAVResource
+        return SimpleCalDAVResource(principalCollections=self.principalCollections())
+
     def provisionDirectory(self):
         if self.directory is None:
             directoryClass = namedClass(config.DirectoryAddressBook.type)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/extensions.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/extensions.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -61,7 +61,7 @@
 import twistedcaldav
 from twistedcaldav import customxml
 from twistedcaldav.customxml import calendarserver_namespace
-from twistedcaldav.util import Alternator, printTracebacks
+from twistedcaldav.util import Alternator
 from twistedcaldav.directory.sudo import SudoDirectoryService
 from twistedcaldav.directory.directory import DirectoryService
 from twistedcaldav.method.report import http_REPORT
@@ -718,8 +718,9 @@
     Bits needed from twext.web2.static
     """
 
-    def __init__(self):
+    def __init__(self, principalCollections=None):
         self.putChildren = {}
+        super(DAVResourceWithChildrenMixin, self).__init__(principalCollections=principalCollections)
 
     def putChild(self, name, child):
         """
@@ -742,7 +743,7 @@
             result = self.makeChild(name)
         return result
 
-    def makeChild(self):
+    def makeChild(self, name):
         # Subclasses with real children need to override this and return the appropriate object
         return None
 

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/index.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/index.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/index.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -113,7 +113,7 @@
 
     def __init__(self, resource):
         """
-        @param resource: the L{twistedcaldav.static.CalDAVFile} resource to
+        @param resource: the L{CalDAVResource} resource to
             index. C{resource} must be a calendar collection (ie.
             C{resource.isPseudoCalendarCollection()} returns C{True}.)
         """
@@ -419,7 +419,7 @@
 
     def __init__(self, resource):
         """
-        @param resource: the L{twistedcaldav.static.CalDAVFile} resource to
+        @param resource: the L{CalDAVResource} resource to
             index.
         """
         super(CalendarIndex, self).__init__(resource)
@@ -920,7 +920,7 @@
 
     def __init__(self, resource):
         """
-        @param resource: the L{twistedcaldav.static.CalDAVFile} resource to
+        @param resource: the L{CalDAVResource} resource to
             index. C{resource} must be a calendar collection (i.e.
             C{resource.isPseudoCalendarCollection()} returns C{True}.)
         """

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/mail.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/mail.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/mail.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -58,15 +58,14 @@
 from twistedcaldav import ical, caldavxml
 from twistedcaldav import memcachepool
 from twistedcaldav.config import config
-from twistedcaldav.directory.util import NotFilePath
 from twistedcaldav.ical import Property
 from twistedcaldav.localization import translationTo
+from twistedcaldav.resource import CalDAVResource
 from twistedcaldav.schedule import deliverSchedulePrivilegeSet
 from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
 from twistedcaldav.scheduling.itip import iTIPRequestStatus
 from twistedcaldav.scheduling.scheduler import IMIPScheduler
 from twistedcaldav.sql import AbstractSQLDatabase
-from twistedcaldav.static import CalDAVFile
 from twistedcaldav.util import AuthorizedHTTPGetter
 from twistedcaldav.stdconfig import DEFAULT_CONFIG, DEFAULT_CONFIG_FILE
 
@@ -174,7 +173,7 @@
 
 
 
-class IMIPInboxResource(CalDAVFile):
+class IMIPInboxResource(CalDAVResource):
     """
     IMIP-delivery Inbox resource.
 
@@ -187,7 +186,7 @@
         """
         assert parent is not None
 
-        CalDAVFile.__init__(self, NotFilePath(isfile=True), principalCollections=parent.principalCollections())
+        CalDAVResource.__init__(self, principalCollections=parent.principalCollections())
 
         self.parent = parent
 

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/__init__.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/__init__.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/__init__.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -17,8 +17,8 @@
 """
 CalDAV methods.
 
-Modules in this package are imported by twistedcaldav.static in order to
-bind methods to CalDAVFile.
+Modules in this package are imported by twistedcaldav.resource in order to
+bind methods to CalDAVResource.
 """
 
 __all__ = [

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/acl.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/acl.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/acl.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -30,7 +30,7 @@
 
 from twistedcaldav.resource import isAddressBookCollectionResource,\
     isPseudoCalendarCollectionResource,\
-    CalendarHomeResource, AddressBookHomeResource
+    CalendarHomeResource, AddressBookHomeResource, CalDAVResource
 
 log = Logger()
 
@@ -51,5 +51,5 @@
             raise HTTPError(responsecode.NOT_ALLOWED)
 
     # Do normal ACL behavior
-    response = (yield super(CalDAVFile, self).http_ACL(request))
+    response = (yield super(CalDAVResource, self).http_ACL(request))
     returnValue(response)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/copymove.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/copymove.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/copymove.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -39,14 +39,8 @@
 )
 
 from twistedcaldav.resource import isCalendarCollectionResource,\
-    isPseudoCalendarCollectionResource
+    isPseudoCalendarCollectionResource, CalDAVResource
 
-CalDAVFile = None               # Pacify PyFlakes; this *should* be fixed, but
-                                # it's not actually an undefined name, as the
-                                # bottom of twistedcaldav.static fixes it up
-                                # for us before any functions in this module
-                                # are invoked.
-
 log = Logger()
 
 @inlineCallbacks
@@ -67,7 +61,7 @@
         # Check with CardDAV first (XXX might want to check EnableCardDAV switch?)
         result = yield maybeCOPYContact(self, request)
         if result is KEEP_GOING:
-            result = yield super(CalDAVFile, self).http_COPY(request)
+            result = yield super(CalDAVResource, self).http_COPY(request)
         returnValue(result)
 
     #
@@ -140,7 +134,7 @@
                 returnValue(result)
 
         # Do default WebDAV action
-        result = (yield super(CalDAVFile, self).http_MOVE(request))
+        result = (yield super(CalDAVResource, self).http_MOVE(request))
         
         if is_calendar_collection:
             # Do some clean up
@@ -215,7 +209,7 @@
         sourcecal:        True if source is in a calendar collection, False otherwise
         sourceparent:     The parent resource for the source
         destination_uri:  The URI of the destination resource
-        destination:      CalDAVFile of destination if special proccesing required,
+        destination:      CalDAVResource of destination if special processing required,
         None otherwise
         destinationcal:   True if the destination is in a calendar collection,
             False otherwise

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/copymove_contact.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/copymove_contact.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/copymove_contact.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -193,7 +193,7 @@
         sourceadbk:        True if source is in an addressbook collection, False otherwise
         sourceparent:     The parent resource for the source
         destination_uri:  The URI of the destination resource
-        destination:      CalDAVFile of destination if special processing required,
+        destination:      CalDAVResource of destination if special processing required,
         None otherwise
         destinationadbk:   True if the destination is in an addressbook collection,
             False otherwise

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/get.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/get.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/get.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -34,7 +34,8 @@
 from twistedcaldav.customxml import TwistedCalendarAccessProperty,\
     calendarserver_namespace
 from twistedcaldav.datafilters.privateevents import PrivateEventFilter
-from twistedcaldav.resource import isPseudoCalendarCollectionResource
+from twistedcaldav.resource import isPseudoCalendarCollectionResource,\
+    CalDAVResource
 
 @inlineCallbacks
 def http_GET(self, request):
@@ -97,5 +98,5 @@
                 returnValue(response)
 
     # Do normal GET behavior
-    response = (yield super(CalDAVFile, self).http_GET(request))
+    response = (yield super(CalDAVResource, self).http_GET(request))
     returnValue(response)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/mkcol.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/mkcol.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/mkcol.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -35,9 +35,9 @@
 
 from twistedcaldav import caldavxml, carddavxml, mkcolxml
 from twistedcaldav.config import config
-from twistedcaldav.resource import isAddressBookCollectionResource
+from twistedcaldav.resource import isAddressBookCollectionResource,\
+    CalDAVResource
 from twistedcaldav.resource import isPseudoCalendarCollectionResource
-from twistedcaldav.static import CalDAVFile
 
 log = Logger()
 
@@ -182,6 +182,6 @@
     
     else:
         # No request body so it is a standard MKCOL
-        result = yield super(CalDAVFile, self).http_MKCOL(request)
+        result = yield super(CalDAVResource, self).http_MKCOL(request)
         returnValue(result)
 

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -31,8 +31,8 @@
 from twistedcaldav.caldavxml import caldav_namespace
 
 from twistedcaldav.method.put_common import StoreCalendarObjectResource
-from twistedcaldav.resource import isPseudoCalendarCollectionResource
-from twistedcaldav.static import CalDAVFile
+from twistedcaldav.resource import isPseudoCalendarCollectionResource,\
+    CalDAVResource
 
 log = Logger()
 
@@ -118,7 +118,7 @@
             raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
 
     else:
-        result = (yield super(CalDAVFile, self).http_PUT(request))
+        result = (yield super(CalDAVResource, self).http_PUT(request))
 
         if not hasattr(request, "extendedLogItems"):
             request.extendedLogItems = {}

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_addressbook_common.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_addressbook_common.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_addressbook_common.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -97,16 +97,16 @@
         Function that does common PUT/COPY/MOVE behavior.
         
         @param request:           the L{twext.web2.server.Request} for the current HTTP request.
-        @param source:            the L{CalDAVFile} for the source resource to copy from, or None if source data
+        @param source:            the L{CalDAVResource} for the source resource to copy from, or None if source data
             is to be read from the request.
         @param source_uri:        the URI for the source resource.
-        @param destination:       the L{CalDAVFile} for the destination resource to copy into.
+        @param destination:       the L{CalDAVResource} for the destination resource to copy into.
         @param destination_uri:   the URI for the destination resource.
         @param vcard:          the C{str} or L{Component} vcard data if there is no source, None otherwise.
         @param sourceadbk:         True if the source resource is in a vcard collection, False otherwise.
         @param destinationadbk:    True if the destination resource is in a vcard collection, False otherwise
-        @param sourceparent:      the L{CalDAVFile} for the source resource's parent collection, or None if source is None.
-        @param destinationparent: the L{CalDAVFile} for the destination resource's parent collection.
+        @param sourceparent:      the L{CalDAVResource} for the source resource's parent collection, or None if source is None.
+        @param destinationparent: the L{CalDAVResource} for the destination resource's parent collection.
         @param deletesource:      True if the source resource is to be deleted on successful completion, False otherwise.
         """
         

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_common.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/put_common.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -135,16 +135,16 @@
         Function that does common PUT/COPY/MOVE behavior.
         
         @param request:           the L{twext.web2.server.Request} for the current HTTP request.
-        @param source:            the L{CalDAVFile} for the source resource to copy from, or None if source data
+        @param source:            the L{CalDAVResource} for the source resource to copy from, or None if source data
             is to be read from the request.
         @param source_uri:        the URI for the source resource.
-        @param destination:       the L{CalDAVFile} for the destination resource to copy into.
+        @param destination:       the L{CalDAVResource} for the destination resource to copy into.
         @param destination_uri:   the URI for the destination resource.
         @param calendar:          the C{str} or L{Component} calendar data if there is no source, None otherwise.
         @param sourcecal:         True if the source resource is in a calendar collection, False otherwise.
         @param destinationcal:    True if the destination resource is in a calendar collection, False otherwise
-        @param sourceparent:      the L{CalDAVFile} for the source resource's parent collection, or None if source is None.
-        @param destinationparent: the L{CalDAVFile} for the destination resource's parent collection.
+        @param sourceparent:      the L{CalDAVResource} for the source resource's parent collection, or None if source is None.
+        @param destinationparent: the L{CalDAVResource} for the destination resource's parent collection.
         @param deletesource:      True if the source resource is to be deleted on successful completion, False otherwise.
         @param isiTIP:                True if relaxed calendar data validation is to be done, False otherwise.
         @param allowImplicitSchedule: True if implicit scheduling should be attempted, False otherwise.

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_addressbook_query.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_addressbook_query.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_addressbook_query.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -104,7 +104,7 @@
         """
         Run a query on the specified address book collection
         accumulating the query responses.
-        @param addrresource: the L{CalDAVFile} for an address book collection.
+        @param addrresource: the L{CalDAVResource} for an address book collection.
         @param uri: the uri for the address book collecton resource.
         """
         
@@ -117,7 +117,7 @@
         def queryAddressBookObjectResource(resource, uri, name, vcard, query_ok = False):
             """
             Run a query on the specified vcard.
-            @param resource: the L{CalDAVFile} for the vcard.
+            @param resource: the L{CalDAVResource} for the vcard.
             @param uri: the uri of the resource.
             @param name: the name of the resource.
             @param vcard: the L{Component} vcard read from the resource.

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_calendar_query.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_calendar_query.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_calendar_query.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -13,7 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
-from twistedcaldav.config import config
 
 """
 CalDAV calendar-query report
@@ -37,6 +36,7 @@
 
 from twistedcaldav.caldavxml import caldav_namespace,\
     NumberOfRecurrencesWithinLimits
+from twistedcaldav.config import config
 from twistedcaldav.customxml import TwistedCalendarAccessProperty
 from twistedcaldav.index import IndexedSearchException
 from twistedcaldav.instance import TooManyInstancesError
@@ -114,14 +114,14 @@
         """
         Run a query on the specified calendar collection
         accumulating the query responses.
-        @param calresource: the L{CalDAVFile} for a calendar collection.
+        @param calresource: the L{CalDAVResource} for a calendar collection.
         @param uri: the uri for the calendar collecton resource.
         """
         
         def queryCalendarObjectResource(resource, uri, name, calendar, timezone, query_ok=False, isowner=True):
             """
             Run a query on the specified calendar.
-            @param resource: the L{CalDAVFile} for the calendar.
+            @param resource: the L{CalDAVResource} for the calendar.
             @param uri: the uri of the resource.
             @param name: the name of the resource.
             @param calendar: the L{Component} calendar read from the resource.
@@ -183,7 +183,7 @@
                     index_query_ok = False
 
                 if not names:
-                    return
+                    returnValue(True)
                   
                 # Now determine which valid resources are readable and which are not
                 ok_resources = []

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_common.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_common.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_common.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -81,7 +81,7 @@
     down from the root. Return a MultiStatus element of all responses.
     
     @param request: the L{IRequest} for the current request.
-    @param resource: the L{CalDAVFile} representing the root to start scanning
+    @param resource: the L{CalDAVResource} representing the root to start scanning
         for calendar collections.
     @param depth: the depth to do the scan.
     @param apply: the function to apply to each calendar collection located
@@ -118,7 +118,7 @@
     down from the root. Return a MultiStatus element of all responses.
     
     @param request: the L{IRequest} for the current request.
-    @param resource: the L{CalDAVFile} representing the root to start scanning
+    @param resource: the L{CalDAVResource} representing the root to start scanning
         for address book collections.
     @param depth: the depth to do the scan.
     @param apply: the function to apply to each address book collection located
@@ -154,7 +154,7 @@
     @param request: the L{IRequest} for the current request.
     @param responses: the list of responses to append the result of this method to.
     @param href: the L{HRef} element of the resource being targeted.
-    @param resource: the L{CalDAVFile} for the targeted resource.
+    @param resource: the L{CalDAVResource} for the targeted resource.
     @param calendar: the L{Component} for the calendar for the resource. This may be None
         if the calendar has not already been read in, in which case the resource
         will be used to get the calendar if needed.
@@ -196,7 +196,7 @@
 
     @param request: the L{IRequest} for the current request.
     @param prop: the L{PropertyContainer} element for the properties of interest.
-    @param resource: the L{CalDAVFile} for the targeted resource.
+    @param resource: the L{CalDAVResource} for the targeted resource.
     @param calendar: the L{Component} for the calendar for the resource. This may be None
         if the calendar has not already been read in, in which case the resource
         will be used to get the calendar if needed.
@@ -221,7 +221,7 @@
     Return property names for all properties on the specified resource.
     @param request: the L{IRequest} for the current request.
     @param prop: the L{PropertyContainer} element for the properties of interest.
-    @param resource: the L{CalDAVFile} for the targeted resource.
+    @param resource: the L{CalDAVResource} for the targeted resource.
     @param calendar: the L{Component} for the calendar for the resource. This may be None
         if the calendar has not already been read in, in which case the resource
         will be used to get the calendar if needed.
@@ -246,7 +246,7 @@
     Return the specified properties on the specified resource.
     @param request: the L{IRequest} for the current request.
     @param prop: the L{PropertyContainer} element for the properties of interest.
-    @param resource: the L{CalDAVFile} for the targeted resource.
+    @param resource: the L{CalDAVResource} for the targeted resource.
     @param calendar: the L{Component} for the calendar for the resource. This may be None
         if the calendar has not already been read in, in which case the resource
         will be used to get the calendar if needed.
@@ -310,7 +310,7 @@
     Return the specified properties on the specified resource.
     @param request: the L{IRequest} for the current request.
     @param props: a list of property elements or qname tuples for the properties of interest.
-    @param resource: the L{CalDAVFile} for the targeted resource.
+    @param resource: the L{CalDAVResource} for the targeted resource.
     @param calendar: the L{Component} for the calendar for the resource. This may be None
         if the calendar has not already been read in, in which case the resource
         will be used to get the calendar if needed.
@@ -389,7 +389,7 @@
     Run a free busy report on the specified calendar collection
     accumulating the free busy info for later processing.
     @param request:     the L{IRequest} for the current request.
-    @param calresource: the L{CalDAVFile} for a calendar collection.
+    @param calresource: the L{CalDAVResource} for a calendar collection.
     @param fbinfo:      the array of busy periods to update.
     @param timerange:   the L{TimeRange} for the query.
     @param matchtotal:  the running total for the number of matches.

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_freebusy.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_freebusy.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/method/report_freebusy.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -62,7 +62,7 @@
         """
         Run a free busy report on the specified calendar collection
         accumulating the free busy info for later processing.
-        @param calresource: the L{CalDAVFile} for a calendar collection.
+        @param calresource: the L{CalDAVResource} for a calendar collection.
         @param uri: the uri for the calendar collecton resource.
         """
         

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notifications.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notifications.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/notifications.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -137,7 +137,7 @@
 
     def __init__(self, resource):
         """
-        @param resource: the L{twistedcaldav.static.CalDAVFile} resource for
+        @param resource: the L{CalDAVResource} resource for
             the notifications collection.)
         """
         self.resource = resource

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/resource.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/resource.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -14,14 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
-from twistedcaldav.index import SyncTokenValidException
-from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
-from uuid import uuid4
-import datetime
-from twisted.python.failure import Failure
-from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeResource
-from twistedcaldav.linkresource import LinkResource, LinkFollowerMixIn
-from twistedcaldav.directory.internal import InternalDirectoryRecord
 
 """
 CalDAV-aware resources.
@@ -37,10 +29,13 @@
     "isAddressBookCollectionResource",
 ]
 
+from urlparse import urlsplit
+from uuid import uuid4
+import datetime
 import urllib
-from urlparse import urlsplit
 import uuid
 
+
 from zope.interface import implements
 
 from twext.python.log import LoggingMixIn
@@ -50,7 +45,9 @@
 from twisted.internet import reactor
 from twisted.internet.defer import Deferred, succeed, maybeDeferred, fail
 from twisted.internet.defer import inlineCallbacks, returnValue
-from twext.web2 import responsecode
+from twisted.python.failure import Failure
+
+from twext.web2 import responsecode, http, http_headers
 from twext.web2.dav import davxml
 from twext.web2.dav.auth import AuthenticationWrapper as SuperAuthenticationWrapper
 from twext.web2.dav.davxml import dav_namespace
@@ -58,31 +55,40 @@
 from twext.web2.dav.resource import AccessDeniedError, DAVPrincipalCollectionResource,\
     davPrivilegeSet
 from twext.web2.dav.resource import TwistedACLInheritable
-from twext.web2.dav.util import joinURL, parentForURL, unimplemented, normalizeURL
+from twext.web2.dav.util import joinURL, parentForURL, normalizeURL
 from twext.web2.http import HTTPError, RedirectResponse, StatusResponse, Response
 from twext.web2.http_headers import MimeType
 from twext.web2.stream import MemoryStream
 
 from twistedcaldav import caldavxml, customxml
 from twistedcaldav import carddavxml
+from twistedcaldav.caldavxml import caldav_namespace
 from twistedcaldav.carddavxml import carddav_namespace
-from twistedcaldav.caldavxml import caldav_namespace
 from twistedcaldav.config import config
-from twistedcaldav.customxml import TwistedCalendarAccessProperty
+from twistedcaldav.customxml import TwistedCalendarAccessProperty,\
+    TwistedScheduleMatchETags
 from twistedcaldav.customxml import calendarserver_namespace
 from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
+from twistedcaldav.datafilters.privateevents import PrivateEventFilter
+from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeResource
 from twistedcaldav.directory.calendar import DirectoryCalendarHomeResource
+from twistedcaldav.directory.internal import InternalDirectoryRecord
 from twistedcaldav.extensions import DAVResource, DAVPrincipalResource,\
-    PropertyNotFoundError
+    PropertyNotFoundError, DAVResourceWithChildrenMixin
 from twistedcaldav.ical import Component
 from twistedcaldav.ical import Component as iComponent
+from twistedcaldav.ical import Property as iProperty
 from twistedcaldav.ical import allowedComponents
 from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
+from twistedcaldav.index import SyncTokenValidException, Index
+from twistedcaldav.linkresource import LinkResource
+from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
+from twistedcaldav.notify import getNodeCacher, NodeCreationException
 from twistedcaldav.notify import getPubSubConfiguration, getPubSubPath,\
     ClientNotifier, getPubSubXMPPURI, getPubSubHeartbeatURI
-from twistedcaldav.notify import getNodeCacher, NodeCreationException
 from twistedcaldav.sharing import SharedCollectionMixin, SharedHomeMixin
 from twistedcaldav.vcard import Component as vComponent
+from twistedcaldav.vcardindex import AddressBookIndex
 
 from txdav.common.icommondatastore import InternalDataStoreError
 
@@ -180,7 +186,7 @@
 
 calendarPrivilegeSet = _calendarPrivilegeSet()
 
-class CalDAVResource (CalDAVComplianceMixIn, SharedCollectionMixin, DAVResource, LoggingMixIn):
+class CalDAVResource (CalDAVComplianceMixIn, SharedCollectionMixin, DAVResourceWithChildrenMixin, DAVResource, LoggingMixIn):
     """
     CalDAV resource.
 
@@ -889,8 +895,14 @@
             else:
                 return super(DAVResource, self).displayName()
         else:
-            return super(DAVResource, self).displayName()
+            result = super(DAVResource, self).displayName()
+            if not result:
+                result = self.name()
+            return result
 
+    def name(self):
+        return None
+
     def resourceID(self):
         if not self.hasDeadProperty(davxml.ResourceID.qname()):
             uuidval = uuid.uuid4()
@@ -923,7 +935,7 @@
         if not self.isCollection(): return False
 
         try:
-            resourcetype = self.readDeadProperty((dav_namespace, "resourcetype"))
+            resourcetype = self.resourceType()
         except HTTPError, e:
             assert e.response.code == responsecode.NOT_FOUND, (
                 "Unexpected response code: %s" % (e.response.code,)
@@ -995,14 +1007,6 @@
 
         return completionDeferred
 
-    def createCalendar(self, request):
-        """
-        See L{ICalDAVResource.createCalendar}.
-        This implementation raises L{NotImplementedError}; a subclass must
-        override it.
-        """
-        unimplemented(self)
-
     @inlineCallbacks
     def deletedCalendar(self, request):
         """
@@ -1104,29 +1108,6 @@
 
         returnValue(PerUserDataFilter(accessUID).filter(caldata))
 
-    def iCalendarRolledup(self, request):
-        """
-        See L{ICalDAVResource.iCalendarRolledup}.
-
-        This implementation raises L{NotImplementedError}; a subclass must
-        override it.
-        """
-        unimplemented(self)
-
-    def iCalendarText(self, name=None):
-        """
-        See L{ICalDAVResource.iCalendarText}.
-
-        This implementation returns the string representation (according to
-        L{str}) of the object returned by L{iCalendar} when given the same
-        arguments.
-
-        Note that L{iCalendar} by default calls this method, which creates
-        an infinite loop.  A subclass must override one of both of these
-        methods.
-        """
-        return str(self.iCalendar(name))
-
     def iCalendarAddressDoNormalization(self, ical):
         """
         Normalize calendar user addresses in the supplied iCalendar object into their
@@ -1155,14 +1136,6 @@
                 return principal
         return None
 
-    def createAddressBook(self, request):
-        """
-        See L{ICalDAVResource.createAddressBook}.
-        This implementation raises L{NotImplementedError}; a subclass must
-        override it.
-        """
-        unimplemented(self)
-
     def vCard(self, name=None):
         """
         See L{ICalDAVResource.vCard}.
@@ -1186,37 +1159,6 @@
         except ValueError:
             return None
 
-    def vCardRolledup(self, request):
-        """
-        See L{ICalDAVResource.vCardRolledup}.
-
-        This implementation raises L{NotImplementedError}; a subclass must
-        override it.
-        """
-        unimplemented(self)
-
-    def vCardText(self, name=None):
-        """
-        See L{ICalDAVResource.vCardText}.
-
-        This implementation returns the string representation (according to
-        L{str}) of the object returned by L{vCard} when given the same
-        arguments.
-
-        Note that L{vCard} by default calls this method, which creates
-        an infinite loop.  A subclass must override one of both of these
-        methods.
-        """
-        return str(self.vCard(name))
-
-    def vCardXML(self, name=None):
-        """
-        See L{ICalDAVResource.vCardXML}.
-        This implementation returns an XML element constructed from the object
-        returned by L{vCard} when given the same arguments.
-        """
-        return carddavxml.AddressData.fromAddress(self.vCard(name))
-
     def supportedReports(self):
         result = super(CalDAVResource, self).supportedReports()
         result.append(davxml.Report(caldavxml.CalendarQuery(),))
@@ -1373,7 +1315,7 @@
         assert self.isCollection()
         
         # Need to lock
-        lock = MemcacheLock("ResourceLock", self.fp.path, timeout=60.0)
+        lock = MemcacheLock("ResourceLock", self.resourceID(), timeout=60.0)
         try:
             try:
                 yield lock.acquire()
@@ -1436,6 +1378,465 @@
 
         return succeed(True)
 
+    #
+    # Stuff from CalDAVFile
+    #
+
+    def checkPreconditions(self, request):
+        """
+        We override the base class to handle the special implicit scheduling weak ETag behavior
+        for compatibility with old clients using If-Match.
+        """
+        
+        if config.Scheduling.CalDAV.ScheduleTagCompatibility:
+            
+            if self.exists() and self.hasDeadProperty(TwistedScheduleMatchETags):
+                etags = self.readDeadProperty(TwistedScheduleMatchETags).children
+                if len(etags) > 1:
+                    # This is almost verbatim from twext.web2.static.checkPreconditions
+                    if request.method not in ("GET", "HEAD"):
+                        
+                        # Loop over each tag and succeed if any one matches, else re-raise last exception
+                        exists = self.exists()
+                        last_modified = self.lastModified()
+                        last_exception = None
+                        for etag in etags:
+                            try:
+                                http.checkPreconditions(
+                                    request,
+                                    entityExists = exists,
+                                    etag = http_headers.ETag(etag),
+                                    lastModified = last_modified,
+                                )
+                            except HTTPError, e:
+                                last_exception = e
+                            else:
+                                break
+                        else:
+                            if last_exception:
+                                raise last_exception
+            
+                    # Check per-method preconditions
+                    method = getattr(self, "preconditions_" + request.method, None)
+                    if method:
+                        response = maybeDeferred(method, request)
+                        response.addCallback(lambda _: request)
+                        return response
+                    else:
+                        return None
+
+        return super(CalDAVResource, self).checkPreconditions(request)
+
+    def createCalendar(self, request):
+        """
+        External API for creating a calendar.  Verify that the parent is a
+        collection, exists, is I{not} a calendar collection; that this resource
+        does not yet exist, then create it.
+
+        @param request: the request used to look up parent resources to
+            validate.
+
+        @type request: L{twext.web2.iweb.IRequest}
+
+        @return: a deferred that fires when a calendar collection has been
+            created in this resource.
+        """
+        if self.exists():
+            self.log_error("Attempt to create collection where file exists: %s" % (self,))
+            raise HTTPError(StatusResponse(responsecode.NOT_ALLOWED, "File exists"))
+
+        # newStore guarantees that we always have a parent calendar home
+        #if not self.fp.parent().isdir():
+        #    log.err("Attempt to create collection with no parent: %s" % (self.fp.path,))
+        #    raise HTTPError(StatusResponse(responsecode.CONFLICT, "No parent collection"))
+
+        #
+        # Verify that no parent collection is a calendar also
+        #
+
+        def _defer(parent):
+            if parent is not None:
+                self.log_error("Cannot create a calendar collection within a calendar collection %s" % (parent,))
+                raise HTTPError(ErrorResponse(
+                    responsecode.FORBIDDEN,
+                    (caldavxml.caldav_namespace, "calendar-collection-location-ok")
+                ))
+
+            return self.createCalendarCollection()
+
+        parent = self._checkParents(request, isPseudoCalendarCollectionResource)
+        parent.addCallback(_defer)
+        return parent
+
+
+    def createCalendarCollection(self):
+        """
+        Internal API for creating a calendar collection.
+
+        @return: a L{Deferred} which fires when the underlying collection has
+            actually been created.
+        """
+        return fail(NotImplementedError())
+
+
+    def createSpecialCollection(self, resourceType=None):
+        #
+        # Create the collection once we know it is safe to do so
+        #
+        def onCollection(status):
+            if status != responsecode.CREATED:
+                raise HTTPError(status)
+
+            self.writeDeadProperty(resourceType)
+            return status
+
+        def onError(f):
+            try:
+                rmdir(self.fp)
+            except Exception, e:
+                log.err("Unable to clean up after failed MKCOL (special resource type: %s): %s" % (e, resourceType,))
+            return f
+
+        d = mkcollection(self.fp)
+        if resourceType is not None:
+            d.addCallback(onCollection)
+        d.addErrback(onError)
+        return d
+
+    @inlineCallbacks
+    def iCalendarRolledup(self, request):
+        if self.isPseudoCalendarCollection():
+
+
+# FIXME: move cache implementation!
+            # Determine the cache key
+#            isvirt = self.isVirtualShare()
+#            if isvirt:
+#                principal = (yield self.resourceOwnerPrincipal(request))
+#                if principal:
+#                    cacheKey = principal.principalUID()
+#                else:
+#                    cacheKey = "unknown"
+#            else:
+#                isowner = (yield self.isOwner(request, adminprincipals=True, readprincipals=True))
+#                cacheKey = "owner" if isowner else "notowner"
+                
+            # Now check for a cached .ics
+#            rolled = self.fp.child(".subscriptions")
+#            if not rolled.exists():
+#                try:
+#                    rolled.makedirs()
+#                except IOError, e:
+#                    self.log_error("Unable to create internet calendar subscription cache directory: %s because of: %s" % (rolled.path, e,))
+#                    raise HTTPError(ErrorResponse(responsecode.INTERNAL_SERVER_ERROR))
+#            cached = rolled.child(cacheKey)
+#            if cached.exists():
+#                try:
+#                    cachedData = cached.open().read()
+#                except IOError, e:
+#                    self.log_error("Unable to open or read internet calendar subscription cache file: %s because of: %s" % (cached.path, e,))
+#                else:
+#                    # Check the cache token
+#                    token, data = cachedData.split("\r\n", 1)
+#                    if token == self.getSyncToken():
+#                        returnValue(data)
+
+            # Generate a monolithic calendar
+            calendar = iComponent("VCALENDAR")
+            calendar.addProperty(iProperty("VERSION", "2.0"))
+
+            # Do some optimisation of access control calculation by determining any inherited ACLs outside of
+            # the child resource loop and supply those to the checkPrivileges on each child.
+            filteredaces = (yield self.inheritedACEsforChildren(request))
+
+            tzids = set()
+            isowner = (yield self.isOwner(request, adminprincipals=True, readprincipals=True))
+            accessPrincipal = (yield self.resourceOwnerPrincipal(request))
+
+            for name, uid, type in self.index().bruteForceSearch(): #@UnusedVariable
+                try:
+                    child = yield request.locateChildResource(self, name)
+                except TypeError:
+                    child = None
+
+                if child is not None:
+                    # Check privileges of child - skip if access denied
+                    try:
+                        yield child.checkPrivileges(request, (davxml.Read(),), inherited_aces=filteredaces)
+                    except AccessDeniedError:
+                        continue
+
+                    # Get the access filtered view of the data
+                    caldata = child.iCalendarTextFiltered(isowner, accessPrincipal.principalUID() if accessPrincipal else "")
+                    try:
+                        subcalendar = iComponent.fromString(caldata)
+                    except ValueError:
+                        continue
+                    assert subcalendar.name() == "VCALENDAR"
+
+                    for component in subcalendar.subcomponents():
+                        
+                        # Only insert VTIMEZONEs once
+                        if component.name() == "VTIMEZONE":
+                            tzid = component.propertyValue("TZID")
+                            if tzid in tzids:
+                                continue
+                            tzids.add(tzid)
+
+                        calendar.addComponent(component)
+
+            # Cache the data
+            data = str(calendar)
+            data = self.getSyncToken() + "\r\n" + data
+#            try:
+#                cached.open(mode='w').write(data)
+#            except IOError, e:
+#                self.log_error("Unable to open or write internet calendar subscription cache file: %s because of: %s" % (cached.path, e,))
+                
+            returnValue(calendar)
+
+        raise HTTPError(ErrorResponse(responsecode.BAD_REQUEST))
+
+    def iCalendarTextFiltered(self, isowner, accessUID=None):
+        try:
+            access = self.readDeadProperty(TwistedCalendarAccessProperty)
+        except HTTPError:
+            access = None
+
+        # Now "filter" the resource calendar data
+        caldata = PrivateEventFilter(access, isowner).filter(self.iCalendarText())
+        if accessUID:
+            caldata = PerUserDataFilter(accessUID).filter(caldata)
+        return str(caldata)
+
+    def iCalendarText(self, name=None):
+        if self.isPseudoCalendarCollection():
+            if name is None:
+                return str(self.iCalendar())
+
+            calendar_resource = self.getChild(name)
+            return calendar_resource.iCalendarText()
+
+        elif self.isCollection():
+            return None
+
+        else:
+            if name is not None:
+                raise AssertionError("name must be None for non-collection calendar resource")
+
+        # FIXME: StoreBridge handles this case
+        raise NotImplementedError
+
+    def createAddressBook(self, request):
+        """
+        External API for creating an addressbook.  Verify that the parent is a
+        collection, exists, is I{not} an addressbook collection; that this resource
+        does not yet exist, then create it.
+
+        @param request: the request used to look up parent resources to
+            validate.
+
+        @type request: L{twext.web2.iweb.IRequest}
+
+        @return: a deferred that fires when an addressbook collection has been
+            created in this resource.
+        """
+        #
+        # request object is required because we need to validate against parent
+        # resources, and we need the request in order to locate the parents.
+        #
+
+        if self.exists():
+            self.log_error("Attempt to create collection where file exists: %s" % (self,))
+            raise HTTPError(StatusResponse(responsecode.NOT_ALLOWED, "File exists"))
+
+        # newStore guarantees that we always have a parent calendar home
+        #if not os.path.isdir(os.path.dirname(self.fp.path)):
+        #    log.err("Attempt to create collection with no parent: %s" % (self.fp.path,))
+        #    raise HTTPError(StatusResponse(responsecode.CONFLICT, "No parent collection"))
+
+        #
+        # Verify that no parent collection is a calendar also
+        #
+
+        def _defer(parent):
+            if parent is not None:
+                self.log_error("Cannot create an address book collection within an address book collection %s" % (parent,))
+                raise HTTPError(ErrorResponse(
+                    responsecode.FORBIDDEN,
+                    (carddavxml.carddav_namespace, "addressbook-collection-location-ok")
+                ))
+
+            return self.createAddressBookCollection()
+
+        parent = self._checkParents(request, isAddressBookCollectionResource)
+        parent.addCallback(_defer)
+        return parent
+
+    def createAddressBookCollection(self):
+        """
+        Internal API for creating an addressbook collection.
+
+        @return: a L{Deferred} which fires when the underlying collection has
+            actually been created.
+        """
+        return fail(NotImplementedError())
+
+    @inlineCallbacks
+    def vCardRolledup(self, request):
+        # TODO: just catenate all the vCards together 
+        yield fail(HTTPError((ErrorResponse(responsecode.BAD_REQUEST))))
+
+    def vCardText(self, name=None):
+        if self.isAddressBookCollection():
+            if name is None:
+                return str(self.vCard())
+
+            vcard_resource = self.getChild(name)
+            return vcard_resource.vCardText()
+
+        elif self.isCollection():
+            return None
+
+        else:
+            if name is not None:
+                raise AssertionError("name must be None for non-collection vcard resource")
+
+        # FIXME: StoreBridge handles this case
+        raise NotImplementedError
+
+    def vCardXML(self, name=None):
+        return carddavxml.AddressData.fromAddressData(self.vCardText(name))
+
+    def supportedPrivileges(self, request):
+        # read-free-busy support on calendar collection and calendar object resources
+        if self.isCollection():
+            return succeed(calendarPrivilegeSet)
+        else:
+            def gotParent(parent):
+                if parent and isCalendarCollectionResource(parent):
+                    return succeed(calendarPrivilegeSet)
+                else:
+                    return super(CalDAVResource, self).supportedPrivileges(request)
+
+            d = self.locateParent(request, request.urlForResource(self))
+            d.addCallback(gotParent)
+            return d
+
+        return super(CalDAVResource, self).supportedPrivileges(request)
+
+    def index(self):
+        """
+        Obtains the index for a calendar collection resource.
+        @return: the index object for this resource.
+        @raise AssertionError: if this resource is not a calendar collection
+            resource.
+        """
+        if self.isAddressBookCollection():
+            return AddressBookIndex(self)
+        else:
+            return Index(self)
+
+    ##
+    # Quota
+    ##
+
+    def quotaSize(self, request):
+        """
+        Get the size of this resource.
+        TODO: Take into account size of dead-properties. Does stat include xattrs size?
+
+        @return: an L{Deferred} with a C{int} result containing the size of the resource.
+        """
+#        if self.isCollection():
+#            @inlineCallbacks
+#            def walktree(top):
+#                """
+#                Recursively descend the directory tree rooted at top,
+#                calling the callback function for each regular file
+#
+#                @param top: L{FilePath} for the directory to walk.
+#                """
+#
+#                total = 0
+#                for f in top.listdir():
+#
+#                    # Ignore the database
+#                    if f.startswith("."):
+#                        continue
+#
+#                    child = top.child(f)
+#                    if child.isdir():
+#                        # It's a directory, recurse into it
+#                        total += yield walktree(child)
+#                    elif child.isfile():
+#                        # It's a file, call the callback function
+#                        total += child.getsize()
+#                    else:
+#                        # Unknown file type, print a message
+#                        pass
+#
+#                returnValue(total)
+#
+#            return walktree(self.fp)
+#        else:
+#            return succeed(self.fp.getsize())
+        return succeed(0)
+
+    ##
+    # Utilities
+    ##
+
+    @staticmethod
+    def _isChildURI(request, uri, immediateChild=True):
+        """
+        Verify that the supplied URI represents a resource that is a child
+        of the request resource.
+        @param request: the request currently in progress
+        @param uri: the URI to test
+        @return: True if the supplied URI is a child resource
+                 False if not
+        """
+        if uri is None: return False
+
+        #
+        # Parse the URI
+        #
+
+        (scheme, host, path, query, fragment) = urlsplit(uri) #@UnusedVariable
+
+        # Request hostname and child uri hostname have to be the same.
+        if host and host != request.headers.getHeader("host"):
+            return False
+
+        # Child URI must start with request uri text.
+        parent = request.uri
+        if not parent.endswith("/"):
+            parent += "/"
+
+        return path.startswith(parent) and (len(path) > len(parent)) and (not immediateChild or (path.find("/", len(parent)) == -1))
+
+    @inlineCallbacks
+    def _checkParents(self, request, test):
+        """
+        @param request: the request being processed.
+        @param test: a callable
+        @return: the closest parent for this resource using the request URI from
+            the given request for which C{test(parent)} evaluates to a true
+            value, or C{None} if no parent matches.
+        """
+        parent = self
+        parent_uri = request.uri
+
+        while True:
+            parent_uri = parentForURL(parent_uri)
+            if not parent_uri: break
+
+            parent = yield request.locateResource(parent_uri)
+
+            if test(parent):
+                returnValue(parent)
+
 class CalendarPrincipalCollectionResource (DAVPrincipalCollectionResource, CalDAVResource):
     """
     CalDAV principal collection.
@@ -1738,6 +2139,7 @@
         self._newStoreCalendarHome = storeHome
         CalDAVResource.__init__(self)
         DirectoryCalendarHomeResource.__init__(self, parent, record)
+
         from twistedcaldav.storebridge import _NewStorePropertiesWrapper
         self._dead_properties = _NewStorePropertiesWrapper(
             self._newStoreCalendarHome.properties()
@@ -1843,6 +2245,7 @@
                  ProtoCalendarCollectionResource)
             similar = ProtoCalendarCollectionResource(
                 self._newStoreCalendarHome,
+                name,
                 principalCollections=self.principalCollections()
             )
         else:
@@ -1982,7 +2385,7 @@
 
     http_ACL = None     # ACL method not supported
 
-class AddressBookHomeResource (LinkFollowerMixIn, SharedHomeMixin, DirectoryAddressBookHomeResource, CalDAVResource):
+class AddressBookHomeResource (SharedHomeMixin, DirectoryAddressBookHomeResource, CalDAVResource):
     """
     Address book home collection resource.
     """
@@ -2057,7 +2460,7 @@
         if name == "notification" and config.Sharing.Enabled and config.Sharing.AddressBooks.Enabled and not config.Sharing.Calendars.Enabled:
             return self.createNotificationsCollection()
 
-        return self.getAddressBookCollection(name)
+        return self.makeChild(name)
 
     def createNotificationsCollection(self):
         
@@ -2075,7 +2478,7 @@
             label="collection")
         return similar
 
-    def getAddressBookCollection(self, name):
+    def makeChild(self, name):
 
         # Check for public/global path
         from twistedcaldav.storebridge import (
@@ -2096,6 +2499,7 @@
             # Local imports.due to circular dependency between modules.
             similar = protoCls(
                 self._newStoreAddressBookHome,
+                name,
                 principalCollections=self.principalCollections()
             )
         else:
@@ -2113,10 +2517,7 @@
         if name not in self.putChildren and name.lower() in (x.lower() for x in self.putChildren):
             return None
 
-        result = super(AddressBookHomeResource, self).getChild(name)
-        if not result:
-            result = self.getAddressBookCollection(name)
-        return result
+        return super(AddressBookHomeResource, self).getChild(name)
 
     def listChildren(self):
         """

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/schedule.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/schedule.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -25,13 +25,12 @@
     "IScheduleInboxResource",
 ]
 
-from twext.web2.dav.http import ErrorResponse, MultiStatusResponse
 
-from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 from twext.web2 import responsecode
 from twext.web2.dav import davxml
 from twext.web2.dav.element.extensions import SyncCollection
 from twext.web2.dav.element.rfc2518 import HRef
+from twext.web2.dav.http import ErrorResponse, MultiStatusResponse
 from twext.web2.dav.noneprops import NonePropertyStore
 from twext.web2.dav.resource import davPrivilegeSet
 from twext.web2.dav.util import joinURL, normalizeURL
@@ -39,12 +38,14 @@
 from twext.web2.http import Response
 from twext.web2.http_headers import MimeType
 
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
+
 from twistedcaldav import caldavxml
 from twistedcaldav.caldavxml import caldav_namespace, Opaque,\
     CalendarFreeBusySet, ScheduleCalendarTransp
 from twistedcaldav.config import config
 from twistedcaldav.customxml import calendarserver_namespace
-from twistedcaldav.extensions import DAVResource, DAVResourceWithChildrenMixin
+from twistedcaldav.extensions import DAVResource
 from twistedcaldav.resource import CalDAVResource, ReadOnlyNoCopyResourceMixIn
 from twistedcaldav.resource import isCalendarCollectionResource
 from twistedcaldav.scheduling.scheduler import CalDAVScheduler, IScheduleScheduler
@@ -88,7 +89,7 @@
 deliverSchedulePrivilegeSet = _schedulePrivilegeSet(True)
 sendSchedulePrivilegeSet = _schedulePrivilegeSet(False)
 
-class CalendarSchedulingCollectionResource (CalDAVResource, DAVResourceWithChildrenMixin):
+class CalendarSchedulingCollectionResource (CalDAVResource):
     """
     CalDAV principal resource.
 
@@ -101,8 +102,7 @@
         """
         assert parent is not None
 
-        CalDAVResource.__init__(self, principalCollections=parent.principalCollections())
-        DAVResourceWithChildrenMixin.__init__(self)
+        super(CalendarSchedulingCollectionResource, self).__init__(principalCollections=parent.principalCollections())
 
         self.parent = parent
 

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/caldav.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/caldav.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/caldav.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -133,7 +133,7 @@
     @inlineCallbacks
     def generateResponse(self, recipient, responses):
         # Hash the iCalendar data for use as the last path element of the URI path
-        name = md5(self.scheduler.calendardata + str(time.time()) + recipient.inbox.fp.path).hexdigest() + ".ics"
+        name = md5(self.scheduler.calendardata + str(time.time()) + recipient.inboxURL).hexdigest() + ".ics"
     
         # Get a resource for the new item
         childURL = joinURL(recipient.inboxURL, name)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/processing.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/scheduling/processing.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -288,7 +288,7 @@
             log.debug("ImplicitProcessing - originator '%s' to recipient '%s' processing METHOD:REQUEST, UID: '%s' - new processed" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
             autoprocessed = self.recipient.principal.getAutoSchedule()
             new_calendar = iTipProcessing.processNewRequest(self.message, self.recipient.cuaddr, autoprocessing=autoprocessed)
-            name =  md5(str(new_calendar) + str(time.time()) + default.fp.path).hexdigest() + ".ics"
+            name =  md5(str(new_calendar) + str(time.time()) + defaultURL).hexdigest() + ".ics"
             
             # Handle auto-reply behavior
             if autoprocessed:
@@ -616,15 +616,15 @@
         resource or by creating a new one.
         
         @param collURL: the C{str} containing the URL of the calendar collection.
-        @param collection: the L{CalDAVFile} for the calendar collection to store the resource in.
+        @param collection: the L{CalDAVResource} for the calendar collection to store the resource in.
         @param name: the C{str} for the resource name to write into, or {None} to write a new resource.
         @param calendar: the L{Component} calendar to write.
-        @return: L{Deferred} -> L{CalDAVFile}
+        @return: L{Deferred} -> L{CalDAVResource}
         """
         
         # Create a new name if one was not provided
         if name is None:
-            name =  md5(str(calendar) + str(time.time()) + collection.fp.path).hexdigest() + ".ics"
+            name =  md5(str(calendar) + str(time.time()) + collURL).hexdigest() + ".ics"
     
         # Get a resource for the new item
         newchildURL = joinURL(collURL, name)
@@ -655,7 +655,7 @@
         @param collURL: the URL of the calendar collection.
         @type name: C{str}
         @param collection: the calendar collection to delete the resource from.
-        @type collection: L{CalDAVFile}
+        @type collection: L{CalDAVResource}
         @param name: the resource name to write into, or {None} to write a new resource.
         @type name: C{str}
         """

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharedcollection.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharedcollection.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharedcollection.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -14,13 +14,14 @@
 # limitations under the License.
 ##
 
+__all__ = [
+    "SharedCollectionResource",
+]
+
 from twisted.internet.defer import inlineCallbacks, returnValue
 
 from twistedcaldav.linkresource import LinkResource
 
-__all__ = [
-    "SharedCollectionResource",
-]
 
 """
 Sharing behavior
@@ -40,6 +41,12 @@
         
         if not hasattr(self, "_linkedResource"):
             self._linkedResource = (yield request.locateResource(self.share.hosturl))
+            
+            # FIXME: this is awkward - because we are "mutation" this object into a virtual share
+            # we must not cache the resource at this URL, otherwise an access of the owner's resource
+            # will return the same virtually shared one which would be wrong.
+            request._forgetResource(self._linkedResource, self.share.hosturl)
+
             ownerPrincipal = (yield self.parent.ownerPrincipal(request))
             self._linkedResource.setVirtualShare(ownerPrincipal, self.share)
         returnValue(self._linkedResource)

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharing.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/sharing.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -24,15 +24,20 @@
 from twext.web2.dav.http import ErrorResponse, MultiStatusResponse
 from twext.web2.dav.resource import TwistedACLInheritable
 from twext.web2.dav.util import allDataFromStream, joinURL
-from twext.web2.http import HTTPError, Response, StatusResponse, XMLResponse
+from twext.web2.http import HTTPError, Response, XMLResponse
+
 from twisted.internet.defer import succeed, inlineCallbacks, DeferredList,\
     returnValue
+
 from twistedcaldav import customxml, caldavxml
 from twistedcaldav.config import config
 from twistedcaldav.customxml import calendarserver_namespace
+from twistedcaldav.linkresource import LinkFollowerMixIn
 from twistedcaldav.sql import AbstractSQLDatabase, db_prefix
+
+from vobject.icalendar import dateTimeToString, utc
+
 from uuid import uuid4
-from vobject.icalendar import dateTimeToString, utc
 import datetime
 import os
 import types
@@ -791,7 +796,7 @@
 
     def __init__(self, resource):
         """
-        @param resource: the L{twistedcaldav.static.CalDAVFile} resource for
+        @param resource: the L{CalDAVResource} resource for
             the shared collection. C{resource} must be a calendar/addressbook collection.)
         """
         self.resource = resource
@@ -917,7 +922,7 @@
         
         return Invite(*[str(item) if type(item) == types.UnicodeType else item for item in row])
 
-class SharedHomeMixin(object):
+class SharedHomeMixin(LinkFollowerMixIn):
     """
     A mix-in for calendar/addressbook homes that defines the operations for manipulating a sharee's
     set of shared calendars.
@@ -1146,7 +1151,7 @@
 
     def __init__(self, resource):   
         """
-        @param resource: the L{twistedcaldav.static.CalDAVFile} resource for
+        @param resource: the L{CalDAVResource} resource for
             the shared collection. C{resource} must be a calendar/addressbook home collection.)
         """
         self.resource = resource

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/simpleresource.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/simpleresource.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/simpleresource.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -14,13 +14,6 @@
 # limitations under the License.
 ##
 
-from twext.web2.dav import davxml
-from twext.web2.dav.noneprops import NonePropertyStore
-from twisted.internet.defer import succeed
-from twistedcaldav.directory.util import NotFilePath
-from twistedcaldav.extensions import DAVFile
-from twistedcaldav.resource import CalDAVResource
-from twistedcaldav.static import CalDAVFile
 
 """
 Implements a simple non-file resource.
@@ -31,61 +24,15 @@
     "SimpleCalDAVResource",
 ]
 
-class SimpleResource (
-    CalDAVResource,
-    DAVFile,
-):
+from twext.web2.dav import davxml
+from twext.web2.dav.noneprops import NonePropertyStore
 
-    allReadACL = davxml.ACL(
-        # Read access for all users.
-        davxml.ACE(
-            davxml.Principal(davxml.All()),
-            davxml.Grant(davxml.Privilege(davxml.Read())),
-            davxml.Protected(),
-        ),
-    )
-    authReadACL = davxml.ACL(
-        # Read access for authenticated users.
-        davxml.ACE(
-            davxml.Principal(davxml.Authenticated()),
-            davxml.Grant(davxml.Privilege(davxml.Read())),
-            davxml.Protected(),
-        ),
-    )
+from twisted.internet.defer import succeed
 
-    def __init__(self, principalCollections, isdir=False, defaultACL=authReadACL):
-        """
-        Make sure it is a collection.
-        """
-        CalDAVResource.__init__(self, principalCollections=principalCollections)
-        DAVFile.__init__(self, NotFilePath(isfile=not isdir,isdir=isdir), principalCollections=principalCollections)
-        self.defaultACL = defaultACL
+from twistedcaldav.resource import CalDAVResource
 
-    def locateChild(self, req, segments):
-        child = self.getChild(segments[0])
-        if child is not None:
-            return (child, segments[1:])
-        return (None, ())
-
-    def getChild(self, name):
-        if name == "":
-            return self
-        else:
-            return self.putChildren.get(name, None)
-
-    def deadProperties(self):
-        if not hasattr(self, "_dead_properties"):
-            self._dead_properties = NonePropertyStore(self)
-        return self._dead_properties
-
-    def etag(self):
-        return None
-
-    def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
-        return succeed(self.defaultACL)
-
-class SimpleCalDAVResource (
-    CalDAVFile,
+class SimpleResource (
+    CalDAVResource,
 ):
 
     allReadACL = davxml.ACL(
@@ -110,21 +57,12 @@
         Make sure it is a collection.
         """
         CalDAVResource.__init__(self, principalCollections=principalCollections)
-        DAVFile.__init__(self, NotFilePath(isfile=not isdir,isdir=isdir), principalCollections=principalCollections)
+        self._isDir = isdir
         self.defaultACL = defaultACL
 
-    def locateChild(self, req, segments):
-        child = self.getChild(segments[0])
-        if child is not None:
-            return (child, segments[1:])
-        return (None, ())
+    def isCollection(self):
+        return self._isDir
 
-    def getChild(self, name):
-        if name == "":
-            return self
-        else:
-            return self.putChildren.get(name, None)
-
     def deadProperties(self):
         if not hasattr(self, "_dead_properties"):
             self._dead_properties = NonePropertyStore(self)
@@ -135,3 +73,5 @@
 
     def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
         return succeed(self.defaultACL)
+
+SimpleCalDAVResource = SimpleResource

Deleted: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/static.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/static.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -1,803 +0,0 @@
-# -*- test-case-name: twistedcaldav.test -*-
-##
-# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-from twistedcaldav.index import Index
-
-"""
-CalDAV-aware static resources.
-"""
-
-__all__ = [
-    "CalDAVFile",
-    "AutoProvisioningFileMixIn",
-    "DirectoryBackedAddressBookFile",
-]
-
-import os
-import errno
-from urlparse import urlsplit
-
-from twext.python.log import Logger
-
-from twisted.internet.defer import fail, succeed, inlineCallbacks, returnValue, maybeDeferred
-from twext.web2 import responsecode, http, http_headers
-from twext.web2.http import HTTPError, StatusResponse
-from twext.web2.dav import davxml
-from twext.web2.dav.fileop import mkcollection, rmdir
-from twext.web2.dav.http import ErrorResponse
-from twext.web2.dav.idav import IDAVResource
-from twext.web2.dav.resource import AccessDeniedError
-from twext.web2.dav.resource import davPrivilegeSet
-from twext.web2.dav.util import parentForURL, bindMethods
-
-from twistedcaldav import caldavxml
-from twistedcaldav import carddavxml
-from twistedcaldav.caldavxml import caldav_namespace
-from twistedcaldav.config import config
-from twistedcaldav.customxml import TwistedCalendarAccessProperty, TwistedScheduleMatchETags
-from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
-from twistedcaldav.extensions import DAVFile, CachingPropertyStore
-from twistedcaldav.linkresource import LinkFollowerMixIn
-
-from twistedcaldav.ical import Component as iComponent
-from twistedcaldav.ical import Property as iProperty
-from twistedcaldav.resource import CalDAVResource, isCalendarCollectionResource, isPseudoCalendarCollectionResource
-from twistedcaldav.resource import isAddressBookCollectionResource
-from twistedcaldav.datafilters.privateevents import PrivateEventFilter
-from twistedcaldav.directorybackedaddressbook import DirectoryBackedAddressBookResource
-from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn
-from twistedcaldav.vcardindex import AddressBookIndex
-
-log = Logger()
-
-class ReadOnlyResourceMixIn(object):
-
-    def http_PUT        (self, request): return responsecode.FORBIDDEN
-    def http_COPY       (self, request): return responsecode.FORBIDDEN
-    def http_MOVE       (self, request): return responsecode.FORBIDDEN
-    def http_DELETE     (self, request): return responsecode.FORBIDDEN
-    def http_MKCOL      (self, request): return responsecode.FORBIDDEN
-
-    def http_MKCALENDAR(self, request):
-        return ErrorResponse(
-            responsecode.FORBIDDEN,
-            (caldav_namespace, "calendar-collection-location-ok")
-        )
-
-
-
-class CalDAVFile (LinkFollowerMixIn, CalDAVResource, DAVFile):
-    """
-    CalDAV-accessible L{DAVFile} resource.
-    """
-#    def __repr__(self):
-#        if self.isCalendarCollection():
-#            return "<%s (calendar collection): %s>" % (self.__class__.__name__, self.fp.path)
-#        else:
-#            return super(CalDAVFile, self).__repr__()
-
-    def __eq__(self, other):
-        if not isinstance(other, CalDAVFile):
-            return False
-        return self.fp.path == other.fp.path
-
-    def checkPreconditions(self, request):
-        """
-        We override the base class to handle the special implicit scheduling weak ETag behavior
-        for compatibility with old clients using If-Match.
-        """
-        
-        if config.Scheduling.CalDAV.ScheduleTagCompatibility:
-            
-            if self.exists() and self.hasDeadProperty(TwistedScheduleMatchETags):
-                etags = self.readDeadProperty(TwistedScheduleMatchETags).children
-                if len(etags) > 1:
-                    # This is almost verbatim from twext.web2.static.checkPreconditions
-                    if request.method not in ("GET", "HEAD"):
-                        
-                        # Loop over each tag and succeed if any one matches, else re-raise last exception
-                        exists = self.exists()
-                        last_modified = self.lastModified()
-                        last_exception = None
-                        for etag in etags:
-                            try:
-                                http.checkPreconditions(
-                                    request,
-                                    entityExists = exists,
-                                    etag = http_headers.ETag(etag),
-                                    lastModified = last_modified,
-                                )
-                            except HTTPError, e:
-                                last_exception = e
-                            else:
-                                break
-                        else:
-                            if last_exception:
-                                raise last_exception
-            
-                    # Check per-method preconditions
-                    method = getattr(self, "preconditions_" + request.method, None)
-                    if method:
-                        response = maybeDeferred(method, request)
-                        response.addCallback(lambda _: request)
-                        return response
-                    else:
-                        return None
-
-        return super(CalDAVFile, self).checkPreconditions(request)
-
-    def deadProperties(self, caching=True):
-        if not hasattr(self, "_dead_properties"):
-            # FIXME: this code should actually be dead, as the property store
-            # should be initialized as part of the traversal process.
- 
-            # Get the property store from super
-            deadProperties = super(CalDAVFile, self).deadProperties()
-
-            if caching:
-                # Wrap the property store in a memory store
-                deadProperties = CachingPropertyStore(deadProperties)
-
-            self._dead_properties = deadProperties
-
-        return self._dead_properties
-
-    ##
-    # CalDAV
-    ##
-
-    def createCalendar(self, request):
-        """
-        External API for creating a calendar.  Verify that the parent is a
-        collection, exists, is I{not} a calendar collection; that this resource
-        does not yet exist, then create it.
-
-        @param request: the request used to look up parent resources to
-            validate.
-
-        @type request: L{twext.web2.iweb.IRequest}
-
-        @return: a deferred that fires when a calendar collection has been
-            created in this resource.
-        """
-        if self.fp.exists():
-            log.err("Attempt to create collection where file exists: %s" % (self.fp.path,))
-            raise HTTPError(StatusResponse(responsecode.NOT_ALLOWED, "File exists"))
-
-        # newStore guarantees that we always have a parent calendar home
-        #if not self.fp.parent().isdir():
-        #    log.err("Attempt to create collection with no parent: %s" % (self.fp.path,))
-        #    raise HTTPError(StatusResponse(responsecode.CONFLICT, "No parent collection"))
-
-        #
-        # Verify that no parent collection is a calendar also
-        #
-        log.msg("Creating calendar collection %s" % (self,))
-
-        def _defer(parent):
-            if parent is not None:
-                log.err("Cannot create a calendar collection within a calendar collection %s" % (parent,))
-                raise HTTPError(ErrorResponse(
-                    responsecode.FORBIDDEN,
-                    (caldavxml.caldav_namespace, "calendar-collection-location-ok")
-                ))
-
-            return self.createCalendarCollection()
-
-        parent = self._checkParents(request, isPseudoCalendarCollectionResource)
-        parent.addCallback(_defer)
-        return parent
-
-
-    def createCalendarCollection(self):
-        """
-        Internal API for creating a calendar collection.
-
-        This will immediately create the collection without performing any
-        verification.  For the normal API, see L{CalDAVFile.createCalendar}.
-
-        The default behavior is to return a failing Deferred; for a working
-        implementation, see L{twistedcaldav.legacy}.
-
-        @return: a L{Deferred} which fires when the underlying collection has
-            actually been created.
-        """
-        return fail(NotImplementedError())
-
-
-    def createSpecialCollection(self, resourceType=None):
-        #
-        # Create the collection once we know it is safe to do so
-        #
-        def onCollection(status):
-            if status != responsecode.CREATED:
-                raise HTTPError(status)
-
-            self.writeDeadProperty(resourceType)
-            return status
-
-        def onError(f):
-            try:
-                rmdir(self.fp)
-            except Exception, e:
-                log.err("Unable to clean up after failed MKCOL (special resource type: %s): %s" % (e, resourceType,))
-            return f
-
-        d = mkcollection(self.fp)
-        if resourceType is not None:
-            d.addCallback(onCollection)
-        d.addErrback(onError)
-        return d
-
-    @inlineCallbacks
-    def iCalendarRolledup(self, request):
-        if self.isPseudoCalendarCollection():
-
-
-# FIXME: move cache implementation!
-            # Determine the cache key
-#            isvirt = self.isVirtualShare()
-#            if isvirt:
-#                principal = (yield self.resourceOwnerPrincipal(request))
-#                if principal:
-#                    cacheKey = principal.principalUID()
-#                else:
-#                    cacheKey = "unknown"
-#            else:
-#                isowner = (yield self.isOwner(request, adminprincipals=True, readprincipals=True))
-#                cacheKey = "owner" if isowner else "notowner"
-                
-            # Now check for a cached .ics
-#            rolled = self.fp.child(".subscriptions")
-#            if not rolled.exists():
-#                try:
-#                    rolled.makedirs()
-#                except IOError, e:
-#                    log.err("Unable to create internet calendar subscription cache directory: %s because of: %s" % (rolled.path, e,))
-#                    raise HTTPError(ErrorResponse(responsecode.INTERNAL_SERVER_ERROR))
-#            cached = rolled.child(cacheKey)
-#            if cached.exists():
-#                try:
-#                    cachedData = cached.open().read()
-#                except IOError, e:
-#                    log.err("Unable to open or read internet calendar subscription cache file: %s because of: %s" % (cached.path, e,))
-#                else:
-#                    # Check the cache token
-#                    token, data = cachedData.split("\r\n", 1)
-#                    if token == self.getSyncToken():
-#                        returnValue(data)
-
-            # Generate a monolithic calendar
-            calendar = iComponent("VCALENDAR")
-            calendar.addProperty(iProperty("VERSION", "2.0"))
-
-            # Do some optimisation of access control calculation by determining any inherited ACLs outside of
-            # the child resource loop and supply those to the checkPrivileges on each child.
-            filteredaces = (yield self.inheritedACEsforChildren(request))
-
-            tzids = set()
-            isowner = (yield self.isOwner(request, adminprincipals=True, readprincipals=True))
-            accessPrincipal = (yield self.resourceOwnerPrincipal(request))
-
-            for name, uid, type in self.index().bruteForceSearch(): #@UnusedVariable
-                try:
-                    child = yield request.locateChildResource(self, name)
-                    child = IDAVResource(child)
-                except TypeError:
-                    child = None
-
-                if child is not None:
-                    # Check privileges of child - skip if access denied
-                    try:
-                        yield child.checkPrivileges(request, (davxml.Read(),), inherited_aces=filteredaces)
-                    except AccessDeniedError:
-                        continue
-
-                    # Get the access filtered view of the data
-                    caldata = child.iCalendarTextFiltered(isowner, accessPrincipal.principalUID() if accessPrincipal else "")
-                    try:
-                        subcalendar = iComponent.fromString(caldata)
-                    except ValueError:
-                        continue
-                    assert subcalendar.name() == "VCALENDAR"
-
-                    for component in subcalendar.subcomponents():
-                        
-                        # Only insert VTIMEZONEs once
-                        if component.name() == "VTIMEZONE":
-                            tzid = component.propertyValue("TZID")
-                            if tzid in tzids:
-                                continue
-                            tzids.add(tzid)
-
-                        calendar.addComponent(component)
-
-            # Cache the data
-            data = str(calendar)
-            data = self.getSyncToken() + "\r\n" + data
-#            try:
-#                cached.open(mode='w').write(data)
-#            except IOError, e:
-#                log.err("Unable to open or write internet calendar subscription cache file: %s because of: %s" % (cached.path, e,))
-                
-            returnValue(calendar)
-
-        raise HTTPError(ErrorResponse(responsecode.BAD_REQUEST))
-
-    def iCalendarTextFiltered(self, isowner, accessUID=None):
-        try:
-            access = self.readDeadProperty(TwistedCalendarAccessProperty)
-        except HTTPError:
-            access = None
-
-        # Now "filter" the resource calendar data
-        caldata = PrivateEventFilter(access, isowner).filter(self.iCalendarText())
-        if accessUID:
-            caldata = PerUserDataFilter(accessUID).filter(caldata)
-        return str(caldata)
-
-    def iCalendarText(self, name=None):
-        if self.isPseudoCalendarCollection():
-            if name is None:
-                return str(self.iCalendar())
-
-            try:
-                calendar_file = self.fp.child(name).open()
-            except IOError, e:
-                if e[0] == errno.ENOENT: return None
-                raise
-
-        elif self.isCollection():
-            return None
-
-        else:
-            if name is not None:
-                raise AssertionError("name must be None for non-collection calendar resource")
-
-            calendar_file = self.fp.open()
-
-        # FIXME: This is blocking I/O
-        try:
-            calendar_data = calendar_file.read()
-        finally:
-            calendar_file.close()
-
-        return calendar_data
-
-    def createAddressBook(self, request):
-        """
-        External API for creating an addressbook.  Verify that the parent is a
-        collection, exists, is I{not} an addressbook collection; that this resource
-        does not yet exist, then create it.
-
-        @param request: the request used to look up parent resources to
-            validate.
-
-        @type request: L{twext.web2.iweb.IRequest}
-
-        @return: a deferred that fires when an addressbook collection has been
-            created in this resource.
-        """
-        #
-        # request object is required because we need to validate against parent
-        # resources, and we need the request in order to locate the parents.
-        #
-
-        if self.fp.exists():
-            log.err("Attempt to create collection where file exists: %s" % (self.fp.path,))
-            raise HTTPError(StatusResponse(responsecode.NOT_ALLOWED, "File exists"))
-
-        # newStore guarantees that we always have a parent calendar home
-        #if not os.path.isdir(os.path.dirname(self.fp.path)):
-        #    log.err("Attempt to create collection with no parent: %s" % (self.fp.path,))
-        #    raise HTTPError(StatusResponse(responsecode.CONFLICT, "No parent collection"))
-
-        #
-        # Verify that no parent collection is a calendar also
-        #
-        log.msg("Creating address book collection %s" % (self,))
-
-        def _defer(parent):
-            if parent is not None:
-                log.err("Cannot create an address book collection within an address book collection %s" % (parent,))
-                raise HTTPError(ErrorResponse(
-                    responsecode.FORBIDDEN,
-                    (carddavxml.carddav_namespace, "addressbook-collection-location-ok")
-                ))
-
-            return self.createAddressBookCollection()
-
-        parent = self._checkParents(request, isAddressBookCollectionResource)
-        parent.addCallback(_defer)
-        return parent
-
-    def createAddressBookCollection(self):
-        """
-        Internal API for creating an addressbook collection.
-
-        This will immediately create the collection without performing any
-        verification.  For the normal API, see L{CalDAVFile.createAddressBook}.
-
-        The default behavior is to return a failing Deferred; for a working
-        implementation, see L{twistedcaldav.legacy}.
-
-        @return: a L{Deferred} which fires when the underlying collection has
-            actually been created.
-        """
-        return fail(NotImplementedError())
-
-    @inlineCallbacks
-    def vCardRolledup(self, request):
-        # TODO: just catenate all the vCards together 
-        yield fail(HTTPError((ErrorResponse(responsecode.BAD_REQUEST))))
-
-    def vCardText(self, name=None):
-        if self.isAddressBookCollection():
-            if name is None:
-                return str(self.vCard())
-
-            try:
-                vcard_file = self.fp.child(name).open()
-            except IOError, e:
-                if e[0] == errno.ENOENT: return None
-                raise
-
-        elif self.isCollection():
-            return None
-
-        else:
-            if name is not None:
-                raise AssertionError("name must be None for non-collection vcard resource")
-
-            vcard_file = self.fp.open()
-
-        # FIXME: This is blocking I/O
-        try:
-            vcard_data = vcard_file.read()
-        finally:
-            vcard_file.close()
-
-        return vcard_data
-
-    def vCardXML(self, name=None):
-        return carddavxml.AddressData.fromAddressData(self.vCardText(name))
-
-    def supportedPrivileges(self, request):
-        # read-free-busy support on calendar collection and calendar object resources
-        if self.isCollection():
-            return succeed(calendarPrivilegeSet)
-        else:
-            def gotParent(parent):
-                if parent and isCalendarCollectionResource(parent):
-                    return succeed(calendarPrivilegeSet)
-                else:
-                    return super(CalDAVFile, self).supportedPrivileges(request)
-
-            d = self.locateParent(request, request.urlForResource(self))
-            d.addCallback(gotParent)
-            return d
-
-        return super(CalDAVFile, self).supportedPrivileges(request)
-
-    ##
-    # Public additions
-    ##
-
-    def index(self):
-        """
-        Obtains the index for a calendar collection resource.
-        @return: the index object for this resource.
-        @raise AssertionError: if this resource is not a calendar collection
-            resource.
-        """
-        if self.isAddressBookCollection():
-            return AddressBookIndex(self)
-        else:
-            return Index(self)
-
-    def listChildren(self):
-        return [
-            child for child in super(CalDAVFile, self).listChildren()
-            if not child.startswith(".")
-        ]
-
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-
-        similar = super(CalDAVFile, self).createSimilarFile(path)
-
-        if isCalendarCollectionResource(self):
-            raise RuntimeError("Calendar collection resources should really "
-                               "be represented by a different class.")
-
-        return similar
-
-    ##
-    # Quota
-    ##
-
-    def quotaSize(self, request):
-        """
-        Get the size of this resource.
-        TODO: Take into account size of dead-properties. Does stat include xattrs size?
-
-        @return: an L{Deferred} with a C{int} result containing the size of the resource.
-        """
-        if self.isCollection():
-            @inlineCallbacks
-            def walktree(top):
-                """
-                Recursively descend the directory tree rooted at top,
-                calling the callback function for each regular file
-
-                @param top: L{FilePath} for the directory to walk.
-                """
-
-                total = 0
-                for f in top.listdir():
-
-                    # Ignore the database
-                    if f.startswith("."):
-                        continue
-
-                    child = top.child(f)
-                    if child.isdir():
-                        # It's a directory, recurse into it
-                        total += yield walktree(child)
-                    elif child.isfile():
-                        # It's a file, call the callback function
-                        total += child.getsize()
-                    else:
-                        # Unknown file type, print a message
-                        pass
-
-                returnValue(total)
-
-            return walktree(self.fp)
-        else:
-            return succeed(self.fp.getsize())
-
-    ##
-    # Utilities
-    ##
-
-    @staticmethod
-    def _isChildURI(request, uri, immediateChild=True):
-        """
-        Verify that the supplied URI represents a resource that is a child
-        of the request resource.
-        @param request: the request currently in progress
-        @param uri: the URI to test
-        @return: True if the supplied URI is a child resource
-                 False if not
-        """
-        if uri is None: return False
-
-        #
-        # Parse the URI
-        #
-
-        (scheme, host, path, query, fragment) = urlsplit(uri) #@UnusedVariable
-
-        # Request hostname and child uri hostname have to be the same.
-        if host and host != request.headers.getHeader("host"):
-            return False
-
-        # Child URI must start with request uri text.
-        parent = request.uri
-        if not parent.endswith("/"):
-            parent += "/"
-
-        return path.startswith(parent) and (len(path) > len(parent)) and (not immediateChild or (path.find("/", len(parent)) == -1))
-
-    @inlineCallbacks
-    def _checkParents(self, request, test):
-        """
-        @param request: the request being processed.
-        @param test: a callable
-        @return: the closest parent for this resource using the request URI from
-            the given request for which C{test(parent)} evaluates to a true
-            value, or C{None} if no parent matches.
-        """
-        parent = self
-        parent_uri = request.uri
-
-        while True:
-            parent_uri = parentForURL(parent_uri)
-            if not parent_uri: break
-
-            parent = yield request.locateResource(parent_uri)
-
-            if test(parent):
-                returnValue(parent)
-
-class AutoProvisioningFileMixIn (LinkFollowerMixIn, AutoProvisioningResourceMixIn):
-    def provision(self):
-        self.provisionFile()
-        return super(AutoProvisioningFileMixIn, self).provision()
-
-
-    def provisionFile(self):
-        if hasattr(self, "_provisioned_file"):
-            return False
-        else:
-            self._provisioned_file = True
-
-        # If the file already exists we can just exit here - there is no need to go further
-        if self.fp.exists():
-            return False
-
-        # At this point the original FilePath did not indicate an existing file, but we should
-        # recheck it to see if some other request sneaked in and already created/provisioned it
-
-        fp = self.fp
-
-        fp.restat(False)
-        if fp.exists():
-            return False
-
-        log.msg("Provisioning file: %s" % (self,))
-
-        if hasattr(self, "parent"):
-            parent = self.parent
-            if not parent.exists() and isinstance(parent, AutoProvisioningFileMixIn):
-                parent.provision()
-
-            assert parent.exists(), "Parent %s of %s does not exist" % (parent, self)
-            assert parent.isCollection(), "Parent %s of %s is not a collection" % (parent, self)
-
-        if self.isCollection():
-            try:
-                fp.makedirs()
-            except OSError:
-                # It's possible someone else created the directory in the meantime...
-                # Check our status again, and re-raise if we're not a collection.
-                if not self.isCollection():
-                    raise
-            fp.changed()
-        else:
-            fp.open("w").close()
-            fp.changed()
-
-        return True
-
-    def _initTypeAndEncoding(self):
-
-        # Handle cases not covered by getTypeAndEncoding()
-        if self.isCollection():
-            self._type = "httpd/unix-directory"
-        else:
-            super(AutoProvisioningFileMixIn, self)._initTypeAndEncoding()
-
-
-class DirectoryBackedAddressBookFile (ReadOnlyResourceMixIn, DirectoryBackedAddressBookResource, CalDAVFile):
-    """
-    Directory-backed address book, supporting directory vcard search.
-    """
-    def __init__(self, path, principalCollections):
-        CalDAVFile.__init__(self, path, principalCollections=principalCollections)
-        DirectoryBackedAddressBookResource.__init__(self)
-
-        # create with permissions, similar to CardDAVOptions in tap.py
-        # FIXME:  /Directory does not need to be in file system unless debug-only caching options are used
-        try:
-            os.mkdir(path)
-            os.chmod(path, 0750)
-            if config.UserName and config.GroupName:
-                import pwd
-                import grp
-                uid = pwd.getpwnam(config.UserName)[2]
-                gid = grp.getgrnam(config.GroupName)[2]
-                os.chown(path, uid, gid)
- 
-            log.msg("Created %s" % (path,))
-            
-        except (OSError,), e:
-            # this is caused by multiprocessor race and is harmless
-            if e.errno != errno.EEXIST:
-                raise
-
-    
-    def getChild(self, name):
-        
-        if name is "":
-            return self
-        else:
-            from twistedcaldav.simpleresource import SimpleCalDAVResource
-            return SimpleCalDAVResource(principalCollections=self.principalCollections())
-       
-    def createSimilarFile(self, path):
-        if self.comparePath(path):
-            return self
-        else:
-            from twistedcaldav.simpleresource import SimpleCalDAVResource
-            return SimpleCalDAVResource(principalCollections=self.principalCollections())
- 
-##
-# Utilities
-##
-
-def locateExistingChild(resource, request, segments):
-    """
-    This C{locateChild()} implementation fails to find children if C{getChild()}
-    doesn't return one.
-    """
-    # If getChild() finds a child resource, return it
-    child = resource.getChild(segments[0])
-    if child is not None:
-        return (child, segments[1:])
-
-    # Otherwise, there is no child
-    return (None, ())
-
-def _calendarPrivilegeSet ():
-    edited = False
-
-    top_supported_privileges = []
-
-    for supported_privilege in davPrivilegeSet.childrenOfType(davxml.SupportedPrivilege):
-        all_privilege = supported_privilege.childOfType(davxml.Privilege)
-        if isinstance(all_privilege.children[0], davxml.All):
-            all_description = supported_privilege.childOfType(davxml.Description)
-            all_supported_privileges = []
-            for all_supported_privilege in supported_privilege.childrenOfType(davxml.SupportedPrivilege):
-                read_privilege = all_supported_privilege.childOfType(davxml.Privilege)
-                if isinstance(read_privilege.children[0], davxml.Read):
-                    read_description = all_supported_privilege.childOfType(davxml.Description)
-                    read_supported_privileges = list(all_supported_privilege.childrenOfType(davxml.SupportedPrivilege))
-                    read_supported_privileges.append(
-                        davxml.SupportedPrivilege(
-                            davxml.Privilege(caldavxml.ReadFreeBusy()),
-                            davxml.Description("allow free busy report query", **{"xml:lang": "en"}),
-                        )
-                    )
-                    all_supported_privileges.append(
-                        davxml.SupportedPrivilege(read_privilege, read_description, *read_supported_privileges)
-                    )
-                    edited = True
-                else:
-                    all_supported_privileges.append(all_supported_privilege)
-            top_supported_privileges.append(
-                davxml.SupportedPrivilege(all_privilege, all_description, *all_supported_privileges)
-            )
-        else:
-            top_supported_privileges.append(supported_privilege)
-
-    assert edited, "Structure of davPrivilegeSet changed in a way that I don't know how to extend for calendarPrivilegeSet"
-
-    return davxml.SupportedPrivilegeSet(*top_supported_privileges)
-
-calendarPrivilegeSet = _calendarPrivilegeSet()
-
-##
-# Attach methods
-##
-
-import twistedcaldav.method
-
-bindMethods(twistedcaldav.method, CalDAVFile)
-
-# FIXME: Little bit of a circular dependency here...
-twistedcaldav.method.acl.CalDAVFile      = CalDAVFile
-twistedcaldav.method.copymove.CalDAVFile = CalDAVFile
-twistedcaldav.method.delete.CalDAVFile   = CalDAVFile
-twistedcaldav.method.get.CalDAVFile      = CalDAVFile
-twistedcaldav.method.mkcol.CalDAVFile    = CalDAVFile
-twistedcaldav.method.propfind.CalDAVFile = CalDAVFile
-twistedcaldav.method.put.CalDAVFile      = CalDAVFile
-
-

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/storebridge.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/storebridge.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -14,8 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
-from twistedcaldav.schedule import ScheduleInboxResource
-from twistedcaldav.extensions import DAVResourceWithChildrenMixin
 
 """
 Wrappers to translate between the APIs in L{txcaldav.icalendarstore} and
@@ -28,40 +26,37 @@
 
 from twisted.internet.defer import succeed, inlineCallbacks, returnValue
 from twisted.internet.protocol import Protocol
+from twisted.python.log import err as logDefaultException
 from twisted.python.util import FancyEqMixin
 
 from twext.python import vcomponent
-from twext.python.filepath import CachingFilePath as FilePath
 from twext.python.log import Logger
 
-from twext.web2.http_headers import ETag, MimeType
+from twext.web2.dav import davxml
+from twext.web2.dav.element.base import dav_namespace
 from twext.web2.dav.http import ErrorResponse, ResponseQueue
-from twext.web2.dav.element.base import dav_namespace
-from twext.web2.responsecode import (
-    FORBIDDEN, NO_CONTENT, NOT_FOUND, CREATED, CONFLICT, PRECONDITION_FAILED,
-    BAD_REQUEST, OK, NOT_IMPLEMENTED, NOT_ALLOWED)
-from twext.web2.dav import davxml
 from twext.web2.dav.resource import TwistedACLInheritable
 from twext.web2.dav.util import parentForURL, allDataFromStream, joinURL, \
     davXMLFromStream
 from twext.web2.http import HTTPError, StatusResponse, Response
+from twext.web2.http_headers import ETag, MimeType
+from twext.web2.responsecode import (
+    FORBIDDEN, NO_CONTENT, NOT_FOUND, CREATED, CONFLICT, PRECONDITION_FAILED,
+    BAD_REQUEST, OK, NOT_IMPLEMENTED, NOT_ALLOWED
+)
 from twext.web2.stream import ProducerStream, readStream, MemoryStream
 
-from twistedcaldav.static import CalDAVFile
-from twistedcaldav.vcard import Component as VCard
-from twistedcaldav.resource import CalDAVResource, GlobalAddressBookResource
-
-from txdav.common.icommondatastore import NoSuchObjectResourceError, \
-    InternalDataStoreError
-from txdav.propertystore.base import PropertyName
-
 from twistedcaldav.caldavxml import ScheduleTag, caldav_namespace
+from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
 from twistedcaldav.notifications import NotificationCollectionResource,\
     NotificationResource
-from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
+from twistedcaldav.resource import CalDAVResource, GlobalAddressBookResource
+from twistedcaldav.schedule import ScheduleInboxResource
 from twistedcaldav.scheduling.implicit import ImplicitScheduler
+from twistedcaldav.vcard import Component as VCard
 
-from twisted.python.log import err as logDefaultException
+from txdav.common.icommondatastore import NoSuchObjectResourceError
+from txdav.propertystore.base import PropertyName
 
 log = Logger()
 
@@ -159,7 +154,47 @@
     return wrap
 
 
+class _NewStoreFileMetaDataHelper(object):
 
+    def name(self):
+        return self._newStoreObject.name()
+
+    def etag(self):
+        # FIXME: far too slow to be used for real, but I needed something to
+        # placate the etag computation in the case where the file doesn't exist
+        # yet (an uncommitted transaction creating this calendar file)
+
+        # FIXME: direct tests
+        try:
+            md5 = self._newStoreObject.md5()
+            if md5:
+                return ETag(md5)
+            else:
+                return ETag(
+                    hashlib.new("md5", self.text()).hexdigest(),
+                    weak=False
+                )
+        except NoSuchObjectResourceError:
+            # FIXME: a workaround for the fact that DELETE still rudely vanishes
+            # the calendar object out from underneath the store, and doesn't
+            # call storeRemove.
+            return None
+
+    def contentType(self):
+        return self._newStoreObject.contentType()
+
+    def contentLength(self):
+        return self._newStoreObject.size()
+
+    def lastModified(self):
+        return self._newStoreObject.modified()
+
+    def creationDate(self):
+        return self._newStoreObject.created()
+
+    def newStoreProperties(self):
+        return self._newStoreObject.properties()
+
 class _CalendarChildHelper(object):
     """
     Methods for things which are like calendars.
@@ -213,21 +248,26 @@
 
     def makeChild(self, name):
         """
-        Create a L{CalendarObjectFile} or L{ProtoCalendarObjectFile} based on a
+        Create a L{CalendarObjectResource} or L{ProtoCalendarObjectResource} based on a
         path object.
         """
 
         newStoreObject = self._newStoreCalendar.calendarObjectWithName(name)
 
         if newStoreObject is not None:
-            similar = CalendarObjectFile(newStoreObject, newStoreObject._path,
-                principalCollections=self._principalCollections)
+            similar = CalendarObjectResource(
+                newStoreObject,
+                principalCollections=self._principalCollections
+            )
         else:
             # FIXME: creation in http_PUT should talk to a specific resource
             # type; this is the domain of StoreCalendarObjectResource.
             # similar = ProtoCalendarObjectFile(self._newStoreCalendar, path)
-            similar = ProtoCalendarObjectFile(self._newStoreCalendar, self._newStoreCalendar._path.child(name),
-                principalCollections=self._principalCollections)
+            similar = ProtoCalendarObjectResource(
+                self._newStoreCalendar,
+                name,
+                principalCollections=self._principalCollections
+            )
 
         # FIXME: tests should be failing without this line.
         # Specifically, http_PUT won't be committing its transaction properly.
@@ -240,7 +280,7 @@
         """
         children = set(self.putChildren.keys())
         children.update(self._newStoreCalendar.listCalendarObjects())
-        return children
+        return sorted(children)
 
 
     def quotaSize(self, request):
@@ -355,8 +395,6 @@
                 l.append(everyObject.dropboxID())
         return l
 
-
-
 class NoDropboxHere(_GetChildHelper):
 
     def isCollection(self):
@@ -535,14 +573,16 @@
             return CREATED
         return readStream(request.stream, t.write).addCallback(done)
 
+    http_MKCOL = None
+    http_MKCALENDAR = None
 
 
-class CalendarAttachment(_GetChildHelper):
+class CalendarAttachment(_NewStoreFileMetaDataHelper, _GetChildHelper):
 
     def __init__(self, calendarObject, attachment, **kw):
         super(CalendarAttachment, self).__init__(**kw)
         self._newStoreCalendarObject = calendarObject
-        self._newStoreAttachment = attachment
+        self._newStoreAttachment = self._newStoreObject = attachment
 
 
     def etag(self):
@@ -597,13 +637,15 @@
         self.__class__ = ProtoCalendarAttachment
         return NO_CONTENT
 
+    http_MKCOL = None
+    http_MKCALENDAR = None
 
     def isCollection(self):
         return False
 
 
 
-class CalendarCollectionResource(_CalendarChildHelper, CalDAVResource, DAVResourceWithChildrenMixin):
+class CalendarCollectionResource(_CalendarChildHelper, CalDAVResource):
     """
     Wrapper around a L{txcaldav.icalendar.ICalendar}.
     """
@@ -614,10 +656,12 @@
         and the arguments required for L{CalDAVResource}.
         """
         super(CalendarCollectionResource, self).__init__(*args, **kw)
-        DAVResourceWithChildrenMixin.__init__(self)
         self._initializeWithCalendar(calendar, home)
 
 
+    def name(self):
+        return self._newStoreCalendar.name()
+
     def isCollection(self):
         return True
 
@@ -766,7 +810,7 @@
             returnValue(FORBIDDEN)
         destination = yield request.locateResource(destinationURI)
         # FIXME: should really use something other than 'fp' attribute.
-        basename = destination.fp.basename()
+        basename = destination.name()
         calendar = self._newStoreCalendar
         calendar.rename(basename)
         CalendarCollectionResource.transform(destination, calendar,
@@ -787,14 +831,15 @@
     def http_PUT(self, request):
         return CONFLICT
 
+    def isCollection(self):
+        return False
 
-
 class ProtoCalendarCollectionResource(CalDAVResource):
     """
     A resource representing a calendar collection which hasn't yet been created.
     """
 
-    def __init__(self, home, *args, **kw):
+    def __init__(self, home, name, *args, **kw):
         """
         A placeholder resource for a calendar collection which does not yet
         exist, but will become a L{CalendarCollectionResource}.
@@ -804,8 +849,9 @@
 
         @type home: L{txcaldav.icalendarstore.ICalendarHome}
         """
+        super(ProtoCalendarCollectionResource, self).__init__(*args, **kw)
         self._newStoreParentHome = home
-        super(ProtoCalendarCollectionResource, self).__init__(*args, **kw)
+        self._name = name
 
 
     def isCollection(self):
@@ -833,10 +879,9 @@
         """
         d = succeed(CREATED)
 
-        calendarName = self.fp.basename()
-        self._newStoreParentHome.createCalendarWithName(calendarName)
+        self._newStoreParentHome.createCalendarWithName(self._name)
         newStoreCalendar = self._newStoreParentHome.calendarWithName(
-            calendarName
+            self._name
         )
         CalendarCollectionResource.transform(
             self, newStoreCalendar, self._newStoreParentHome
@@ -849,6 +894,9 @@
         return False
 
 
+    def name(self):
+        return self._name
+
     def provision(self):
         """
         This resource should do nothing if it's provisioned.
@@ -862,7 +910,7 @@
 
 
 
-class CalendarObjectFile(CalDAVFile, FancyEqMixin):
+class CalendarObjectResource(_NewStoreFileMetaDataHelper, CalDAVResource, FancyEqMixin):
     """
     A resource wrapping a calendar object.
     """
@@ -871,19 +919,15 @@
 
     def __init__(self, calendarObject, *args, **kw):
         """
-        Construct a L{CalendarObjectFile} from an L{ICalendarObject}.
+        Construct a L{CalendarObjectResource} from an L{ICalendarObject}.
 
         @param calendarObject: The storage for the calendar object.
         @type calendarObject: L{txcaldav.icalendarstore.ICalendarObject}
         """
-        super(CalendarObjectFile, self).__init__(*args, **kw)
+        super(CalendarObjectResource, self).__init__(*args, **kw)
         self._initializeWithObject(calendarObject)
 
 
-    def isCollection(self):
-        return False
-
-
     def inNewTransaction(self, request):
         """
         Implicit auto-replies need to span multiple transactions.  Clean out
@@ -910,41 +954,15 @@
         return txn
 
 
+    def isCollection(self):
+        return False
+
+
     def exists(self):
         # FIXME: Tests
         return True
 
 
-    def name(self):
-        return self._newStoreObject.name()
-
-
-    def etag(self):
-        # FIXME: far too slow to be used for real, but I needed something to
-        # placate the etag computation in the case where the file doesn't exist
-        # yet (an uncommited transaction creating this calendar file)
-
-        # FIXME: direct tests
-        try:
-            md5 = self._newStoreObject.md5()
-            if md5:
-                return ETag(md5)
-            else:
-                return ETag(
-                    hashlib.new("md5", self.iCalendarText()).hexdigest(),
-                    weak=False
-                )
-        except (NoSuchObjectResourceError, InternalDataStoreError):
-            # FIXME: a workaround for the fact that DELETE still rudely vanishes
-            # the calendar object out from underneath the store, and doesn't
-            # call storeRemove.
-            return None
-
-
-    def newStoreProperties(self):
-        return self._newStoreObject.properties()
-
-
     def quotaSize(self, request):
         # FIXME: tests
         return succeed(len(self._newStoreObject.iCalendarText()))
@@ -1071,7 +1089,7 @@
             # FIXME: clean this up with a 'transform' method
             self._newStoreParentCalendar = storeCalendar
             del self._newStoreObject
-            self.__class__ = ProtoCalendarObjectFile
+            self.__class__ = ProtoCalendarObjectResource
 
             # Adjust quota
             if myquota is not None:
@@ -1108,13 +1126,14 @@
 
 
 
-class ProtoCalendarObjectFile(CalDAVFile, FancyEqMixin):
+class ProtoCalendarObjectResource(CalDAVResource, FancyEqMixin):
 
     compareAttributes = '_newStoreParentCalendar'.split()
 
-    def __init__(self, parentCalendar, *a, **kw):
-        super(ProtoCalendarObjectFile, self).__init__(*a, **kw)
+    def __init__(self, parentCalendar, name, *a, **kw):
+        super(ProtoCalendarObjectResource, self).__init__(*a, **kw)
         self._newStoreParentCalendar = parentCalendar
+        self._name = name
 
 
     @inlineCallbacks
@@ -1124,9 +1143,9 @@
             (yield allDataFromStream(stream))
         )
         self._newStoreParentCalendar.createCalendarObjectWithName(
-            self.fp.basename(), component
+            self.name(), component
         )
-        CalendarObjectFile.transform(self, self._newStoreParentCalendar.calendarObjectWithName(self.fp.basename()))
+        CalendarObjectResource.transform(self, self._newStoreParentCalendar.calendarObjectWithName(self.name()))
         returnValue(CREATED)
 
 
@@ -1139,7 +1158,7 @@
 
 
     def name(self):
-        return self.fp.basename()
+        return self._name
 
     def quotaSize(self, request):
         # FIXME: tests, workingness
@@ -1198,20 +1217,25 @@
 
     def makeChild(self, name):
         """
-        Create a L{AddressBookObjectFile} or L{ProtoAddressBookObjectFile} based on a
+        Create a L{AddressBookObjectResource} or L{ProtoAddressBookObjectResource} based on a
         path object.
         """
         newStoreObject = self._newStoreAddressBook.addressbookObjectWithName(name)
 
         if newStoreObject is not None:
-            similar = AddressBookObjectFile(newStoreObject, newStoreObject._path,
-                principalCollections=self._principalCollections)
+            similar = AddressBookObjectResource(
+                newStoreObject,
+                principalCollections=self._principalCollections
+            )
         else:
             # FIXME: creation in http_PUT should talk to a specific resource
             # type; this is the domain of StoreAddressBookObjectResource.
             # similar = ProtoAddressBookObjectFile(self._newStoreAddressBook, path)
-            similar = ProtoAddressBookObjectFile(self._newStoreAddressBook, self._newStoreAddressBook._path.child(name),
-                principalCollections=self._principalCollections)
+            similar = ProtoAddressBookObjectResource(
+                self._newStoreAddressBook,
+                name,
+                principalCollections=self._principalCollections
+            )
 
         # FIXME: tests should be failing without this line.
         # Specifically, http_PUT won't be committing its transaction properly.
@@ -1224,7 +1248,7 @@
         """
         children = set(self.putChildren.keys())
         children.update(self._newStoreAddressBook.listAddressbookObjects())
-        return children
+        return sorted(children)
 
 
 
@@ -1234,7 +1258,7 @@
 
 
 
-class AddressBookCollectionResource(_AddressBookChildHelper, CalDAVResource, DAVResourceWithChildrenMixin):
+class AddressBookCollectionResource(_AddressBookChildHelper, CalDAVResource):
     """
     Wrapper around a L{txcarddav.iaddressbook.IAddressBook}.
     """
@@ -1245,10 +1269,12 @@
         and the arguments required for L{CalDAVResource}.
         """
         super(AddressBookCollectionResource, self).__init__(*args, **kw)
-        DAVResourceWithChildrenMixin.__init__(self)
         self._initializeWithAddressBook(addressbook, home)
 
 
+    def name(self):
+        return self._newStoreAddressBook.name()
+
     def isCollection(self):
         return True
 
@@ -1377,7 +1403,7 @@
             returnValue(FORBIDDEN)
         destination = yield request.locateResource(destinationURI)
         # FIXME: should really use something other than 'fp' attribute.
-        basename = destination.fp.basename()
+        basename = destination.name()
         addressbook = self._newStoreAddressBook
         addressbook.rename(basename)
         AddressBookCollectionResource.transform(destination, addressbook,
@@ -1393,7 +1419,7 @@
     A resource representing an addressbook collection which hasn't yet been created.
     """
 
-    def __init__(self, home, *args, **kw):
+    def __init__(self, home, name, *args, **kw):
         """
         A placeholder resource for an addressbook collection which does not yet
         exist, but will become a L{AddressBookCollectionResource}.
@@ -1403,8 +1429,9 @@
 
         @type home: L{txcarddav.iaddressbookstore.IAddressBookHome}
         """
+        super(ProtoAddressBookCollectionResource, self).__init__(*args, **kw)
         self._newStoreParentHome = home
-        super(ProtoAddressBookCollectionResource, self).__init__(*args, **kw)
+        self._name = name
 
 
     def isCollection(self):
@@ -1434,10 +1461,9 @@
         """
         d = succeed(CREATED)
 
-        Name = self.fp.basename()
-        self._newStoreParentHome.createAddressBookWithName(Name)
+        self._newStoreParentHome.createAddressBookWithName(self._name)
         newStoreAddressBook = self._newStoreParentHome.addressbookWithName(
-            Name
+            self._name
         )
         AddressBookCollectionResource.transform(
             self, newStoreAddressBook, self._newStoreParentHome
@@ -1450,6 +1476,9 @@
         return False
 
 
+    def name(self):
+        return self._name
+
     def provision(self):
         """
         This resource should do nothing if it's provisioned.
@@ -1475,7 +1504,7 @@
     pass
 
 
-class AddressBookObjectFile(CalDAVFile, FancyEqMixin):
+class AddressBookObjectResource(_NewStoreFileMetaDataHelper, CalDAVResource, FancyEqMixin):
     """
     A resource wrapping a addressbook object.
     """
@@ -1484,12 +1513,12 @@
 
     def __init__(self, Object, *args, **kw):
         """
-        Construct a L{AddressBookObjectFile} from an L{IAddressBookObject}.
+        Construct a L{AddressBookObjectResource} from an L{IAddressBookObject}.
 
         @param Object: The storage for the addressbook object.
         @type Object: L{txcarddav.iaddressbookstore.IAddressBookObject}
         """
-        super(AddressBookObjectFile, self).__init__(*args, **kw)
+        super(AddressBookObjectResource, self).__init__(*args, **kw)
         self._initializeWithObject(Object)
 
 
@@ -1508,7 +1537,7 @@
         homeUID = self._newStoreObject._addressbook._addressbookHome.uid()
         store = self._newStoreObject._transaction.store()
         txn = store.newTransaction("new AB transaction for " + self._newStoreObject.name())
-        newObject = (txn.HomeWithUID(homeUID)
+        newObject = (txn.addressbookHomeWithUID(homeUID)
                         .addressbookWithName(Name)
                         .addressbookObjectWithName(objectName))
         request._newStoreTransaction = txn
@@ -1526,35 +1555,6 @@
         return True
 
 
-    def name(self):
-        return self._newStoreObject.name()
-
-    def etag(self):
-        # FIXME: far too slow to be used for real, but I needed something to
-        # placate the etag computation in the case where the file doesn't exist
-        # yet (an uncommited transaction creating this addressbook file)
-
-        # FIXME: direct tests
-        try:
-            md5 = self._newStoreObject.md5()
-            if md5:
-                return ETag(md5)
-            else:
-                return ETag(
-                    hashlib.new("md5", self.vCardText()).hexdigest(),
-                    weak=False
-                )
-        except (NoSuchObjectResourceError, InternalDataStoreError):
-            # FIXME: a workaround for the fact that DELETE still rudely vanishes
-            # the addressbook object out from underneath the store, and doesn't
-            # call storeRemove.
-            return None
-
-
-    def newStoreProperties(self):
-        return self._newStoreObject.properties()
-
-
     def quotaSize(self, request):
         # FIXME: tests
         return succeed(len(self._newStoreObject.vCardText()))
@@ -1565,6 +1565,13 @@
         return self._newStoreObject.vCardText()
 
 
+    def render(self, request):
+        output = self.vCardText()
+
+        response = Response(200, {}, output)
+        response.headers.setHeader("content-type", self.contentType())
+        return response
+
     @requiresPermissions(fromParent=[davxml.Unbind()])
     def http_DELETE(self, request):
         """
@@ -1607,7 +1614,7 @@
             # FIXME: clean this up with a 'transform' method
             self._newStoreParentAddressBook = storeAddressBook
             del self._newStoreObject
-            self.__class__ = ProtoAddressBookObjectFile
+            self.__class__ = ProtoAddressBookObjectResource
 
             # Adjust quota
             if myquota is not None:
@@ -1633,15 +1640,15 @@
 
 
 
-class ProtoAddressBookObjectFile(CalDAVFile, FancyEqMixin):
+class ProtoAddressBookObjectResource(CalDAVResource, FancyEqMixin):
 
     compareAttributes = '_newStoreParentAddressBook'.split()
 
-    def __init__(self, parentAddressBook, *a, **kw):
-        super(ProtoAddressBookObjectFile, self).__init__(*a, **kw)
+    def __init__(self, parentAddressBook, name, *a, **kw):
+        super(ProtoAddressBookObjectResource, self).__init__(*a, **kw)
         self._newStoreParentAddressBook = parentAddressBook
+        self._name = name
 
-
     @inlineCallbacks
     def storeStream(self, stream):
         # FIXME: direct tests 
@@ -1649,9 +1656,9 @@
             (yield allDataFromStream(stream))
         )
         self._newStoreParentAddressBook.createAddressBookObjectWithName(
-            self.fp.basename(), component
+            self.name(), component
         )
-        AddressBookObjectFile.transform(self, self._newStoreParentAddressBook.addressbookObjectWithName(self.fp.basename()))
+        AddressBookObjectResource.transform(self, self._newStoreParentAddressBook.addressbookObjectWithName(self.name()))
         returnValue(CREATED)
 
 
@@ -1664,7 +1671,7 @@
 
 
     def name(self):
-        return self.fp.basename()
+        return self._name
 
     def quotaSize(self, request):
         # FIXME: tests, workingness
@@ -1835,7 +1842,7 @@
         """
         d = succeed(CREATED)
 
-        notificationName = self.fp.basename()
+        notificationName = self.name()
         self._newStoreParentHome.createChildWithName(notificationName)
         newStoreNotification = self._newStoreParentHome.childWithName(
             notificationName
@@ -1871,7 +1878,7 @@
 
     def __init__(self, notificationObject, *args, **kw):
         """
-        Construct a L{CalendarObjectFile} from an L{ICalendarObject}.
+        Construct a L{CalendarObjectResource} from an L{ICalendarObject}.
 
         @param calendarObject: The storage for the calendar object.
         @type calendarObject: L{txcaldav.icalendarstore.ICalendarObject}

Modified: CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/vcardindex.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/vcardindex.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/twistedcaldav/vcardindex.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -221,7 +221,7 @@
 
     def __init__(self, resource):
         """
-        @param resource: the L{twistedcaldav.static.CalDAVFile} resource to
+        @param resource: the L{CalDAVResource} resource to
             index. C{resource} must be an addressbook collection (ie.
             C{resource.isAddressBookCollection()} returns C{True}.)
         """

Modified: CalendarServer/branches/new-store-no-caldavfile/txcaldav/calendarstore/file.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/txcaldav/calendarstore/file.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/txcaldav/calendarstore/file.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -281,7 +281,7 @@
     def component(self):
         if self._component is not None:
             return self._component
-        text = self.iCalendarText()
+        text = self.text()
 
         try:
             component = VComponent.fromString(text)
@@ -293,7 +293,7 @@
         return component
 
 
-    def iCalendarText(self):
+    def text(self):
         if self._component is not None:
             return str(self._component)
         try:
@@ -319,6 +319,7 @@
             )
         return text
 
+    iCalendarText = text
 
     def uid(self):
         if not hasattr(self, "_uid"):
@@ -440,7 +441,7 @@
         """
         self._attachment = attachment
         self._contentType = contentType
-        self._file = self._attachment._computePath().open("w")
+        self._file = self._attachment._path.open("w")
 
 
     def write(self, data):
@@ -452,7 +453,7 @@
         # FIXME: do anything
         self._file.close()
 
-        md5 = hashlib.md5(self._attachment._computePath().getContent()).hexdigest()
+        md5 = hashlib.md5(self._attachment._path.getContent()).hexdigest()
         props = self._attachment.properties()
         props[contentTypeKey] = GETContentType(generateContentType(self._contentType))
         props[md5key] = TwistedGETContentMD5.fromString(md5)
@@ -491,7 +492,7 @@
         return PropertyStore(
             self._calendarObject._parentCollection._home.peruser_uid(),
             self._calendarObject._parentCollection._home.uid(),
-            self._computePath
+            lambda :self._path
         )
 
 
@@ -502,12 +503,12 @@
         # FIXME: makeConnection
         # FIXME: actually stream
         # FIMXE: connectionLost
-        protocol.dataReceived(self._computePath().getContent())
+        protocol.dataReceived(self._path.getContent())
         # FIXME: ConnectionDone, not NotImplementedError
         protocol.connectionLost(Failure(NotImplementedError()))
 
-
-    def _computePath(self):
+    @property
+    def _path(self):
         dropboxPath = self._calendarObject._dropboxPath()
         return dropboxPath.child(self.name())
 

Modified: CalendarServer/branches/new-store-no-caldavfile/txcarddav/addressbookstore/file.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/txcarddav/addressbookstore/file.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/txcarddav/addressbookstore/file.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -211,7 +211,7 @@
     def component(self):
         if self._component is not None:
             return self._component
-        text = self.vCardText()
+        text = self.text()
 
         try:
             component = VComponent.fromString(text)
@@ -223,7 +223,7 @@
         return component
 
 
-    def vCardText(self):
+    def text(self):
         if self._component is not None:
             return str(self._component)
         try:
@@ -249,6 +249,7 @@
             )
         return text
 
+    vCardText = text
 
     def uid(self):
         if not hasattr(self, "_uid"):

Modified: CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/file.py
===================================================================
--- CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/file.py	2010-07-23 16:50:33 UTC (rev 5925)
+++ CalendarServer/branches/new-store-no-caldavfile/txdav/common/datastore/file.py	2010-07-23 17:06:51 UTC (rev 5926)
@@ -308,13 +308,13 @@
         """
         Return a set of the names of the child resources.
         """
-        return set(
+        return sorted(set(
             [child.name() for child in self._newChildren.itervalues()]
         ) | set(
             name
             for name in self._path.listdir()
             if not name.startswith(".")
-        )
+        ))
 
     def childWithName(self, name):
         child = self._newChildren.get(name)
@@ -629,7 +629,7 @@
 
 
     def _updateSyncToken(self, reset=False):
-        # FIXME: add locking a-la CalDAVFile.bumpSyncToken
+        # FIXME: add locking a-la CalDAVResource.bumpSyncToken
         # FIXME: tests for desired concurrency properties
         ctag = PropertyName.fromString(GETCTag.sname())
         props = self.properties()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100723/ad04e355/attachment-0001.html>


More information about the calendarserver-changes mailing list