[CalendarServer-changes] [5607] CalendarServer/branches/new-store/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Fri May 14 22:04:41 PDT 2010


Revision: 5607
          http://trac.macosforge.org/projects/calendarserver/changeset/5607
Author:   glyph at apple.com
Date:     2010-05-14 22:04:39 -0700 (Fri, 14 May 2010)
Log Message:
-----------
Start moving discrete resource behavior types into discrete classes.

Modified Paths:
--------------
    CalendarServer/branches/new-store/twistedcaldav/static.py
    CalendarServer/branches/new-store/twistedcaldav/test/test_wrapping.py

Added Paths:
-----------
    CalendarServer/branches/new-store/twistedcaldav/storebridge.py

Modified: CalendarServer/branches/new-store/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/new-store/twistedcaldav/static.py	2010-05-15 04:55:35 UTC (rev 5606)
+++ CalendarServer/branches/new-store/twistedcaldav/static.py	2010-05-15 05:04:39 UTC (rev 5607)
@@ -110,7 +110,6 @@
     NotificationResource
 
 from txcaldav.calendarstore.file import CalendarStore
-from txdav.propertystore.base import PropertyName
 
 log = Logger()
 
@@ -129,69 +128,7 @@
         )
 
 
-class _NewStorePropertiesWrapper(object):
-    """
-    Wrap a new-style property store (a L{txdav.idav.IPropertyStore}) in the old-
-    style interface for compatibility with existing code.
-    """
-    
-    def __init__(self, newPropertyStore):
-        """
-        Initialize an old-style property store from a new one.
 
-        @param newPropertyStore: the new-style property store.
-        @type newPropertyStore: L{txdav.idav.IPropertyStore}
-        """
-        self._newPropertyStore = newPropertyStore
-
-    @classmethod
-    def _convertKey(cls, qname):
-        namespace, name = qname
-        return PropertyName(namespace, name)
-
-
-    # FIXME 'uid' here should be verifying something.
-    def get(self, qname, uid=None):
-        """
-        
-        """
-        try:
-            return self._newPropertyStore[self._convertKey(qname)]
-        except KeyError:
-            raise HTTPError(StatusResponse(
-                    responsecode.NOT_FOUND,
-                    "No such property: {%s}%s" % qname))
-
-
-    def set(self, property, uid=None):
-        """
-        
-        """
-        self._newPropertyStore[self._convertKey(property.qname())] = property
-
-
-    def delete(self, qname, uid=None):
-        """
-        
-        """
-        del self._newPropertyStore[self._convertKey(qname)]
-
-
-    def contains(self, qname, uid=None, cache=True):
-        """
-        
-        """
-        return (self._convertKey(qname) in self._newPropertyStore)
-
-
-    def list(self, uid=None, filterByUID=True, cache=True):
-        """
-        
-        """
-        return [(pname.namespace, pname.name) for pname in 
-                self._newPropertyStore.keys()]
-
-
 class CalDAVFile (LinkFollowerMixIn, CalDAVResource, DAVFile):
     """
     CalDAV-accessible L{DAVFile} resource.
@@ -262,7 +199,7 @@
 
             if caching:
                 # Wrap the property store in a memory store
-                 deadProperties = CachingPropertyStore(deadProperties)
+                deadProperties = CachingPropertyStore(deadProperties)
 
             self._dead_properties = deadProperties
 
@@ -321,20 +258,13 @@
         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.
         """
-        # d = self.createSpecialCollection(davxml.ResourceType.calendar)
-        d = succeed(responsecode.CREATED)
-        calendarName = self.fp.basename()
-        self._newStoreParentHome.createCalendarWithName(calendarName)
-        self._newStoreCalendar = self._newStoreParentHome.calendarWithName(
-            calendarName
-        )
-        self._dead_properties = _NewStorePropertiesWrapper(
-            self._newStoreCalendar.properties()
-        )
-        return d
+        return fail(NotImplementedError())
 
 
     def isCollection(self):
@@ -707,59 +637,9 @@
         similar = super(CalDAVFile, self).createSimilarFile(path)
 
         if isCalendarCollectionResource(self):
-            similar._newStoreObject = \
-                self._newStoreCalendar.calendarObjectWithName(
-                    similar.fp.basename()
-                )
-            if similar._newStoreObject is not None:
-                # FIXME: what about creation in http_PUT?
-                similar._dead_properties = _NewStorePropertiesWrapper(
-                    similar._newStoreObject.properties()
-                )
-            # FIXME: tests should fail without this:
-            # self.propagateTransaction(similar)
+            raise RuntimeError("Calendar collection resources should really "
+                               "be represented by a different class.")
 
-            # Short-circuit stat with information we know to be true at this point
-            if isinstance(path, FilePath) and hasattr(self, "knownChildren"):
-                if path.basename() in self.knownChildren:
-                    path.existsCached = True
-                    path.isDirCached = False
-
-            #
-            # Override the dead property store
-            #
-            superDeadProperties = similar.deadProperties
-
-            def deadProperties():
-                if not hasattr(similar, "_dead_properties"):
-                    similar._dead_properties = self.propertyCollection().propertyStoreForChild(
-                        similar,
-                        superDeadProperties(caching=False)
-                    )
-                return similar._dead_properties
-
-            similar.deadProperties = deadProperties
-
-            #
-            # Override DELETE, MOVE
-            #
-            for method in ("DELETE", "MOVE"):
-                method = "http_" + method
-                original = getattr(similar, method)
-
-                @inlineCallbacks
-                def override(request, original=original):
-
-                    # Call original method (which is deferred)
-                    response = (yield original(request))
-
-                    # Wipe the cache
-                    similar.deadProperties().flushCache()
-
-                    returnValue(response)
-
-                setattr(similar, method, override)
-
         return similar
 
     ##
@@ -1131,24 +1011,31 @@
         return self.createSimilarFile(self.fp.child(name).path)
 
     def createSimilarFile(self, path):
+
         if self.comparePath(path):
             return self
         else:
-            similar = CalDAVFile(
-                path, principalCollections=self.principalCollections()
+            if not isinstance(path, FilePath):
+                path = FilePath(path)
+            newCalendar = self._newStoreCalendarHome.calendarWithName(
+                path.basename()
             )
-            similar.clientNotifier = self.clientNotifier
-            similar._newStoreParentHome = self._newStoreCalendarHome
-            similar._newStoreCalendar = (
-                self._newStoreCalendarHome.calendarWithName(
-                    similar.fp.basename()
+            if newCalendar is None:
+                # Local imports.due to circular dependency between modules.
+                from twistedcaldav.storebridge import (
+                     ProtoCalendarCollectionFile)
+                similar = ProtoCalendarCollectionFile(
+                    self._newStoreCalendarHome,
+                    path, principalCollections=self.principalCollections()
                 )
-            )
-            if similar._newStoreCalendar is not None:
-                similar._dead_properties = _NewStorePropertiesWrapper(
-                    similar._newStoreCalendar.properties()
+            else:
+                from twistedcaldav.storebridge import CalendarCollectionFile
+                similar = CalendarCollectionFile(
+                    newCalendar, self._newStoreCalendarHome,
+                    path, principalCollections=self.principalCollections()
                 )
             self.propagateTransaction(similar)
+            similar.clientNotifier = self.clientNotifier
             return similar
 
     def getChild(self, name):

Added: CalendarServer/branches/new-store/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/new-store/twistedcaldav/storebridge.py	                        (rev 0)
+++ CalendarServer/branches/new-store/twistedcaldav/storebridge.py	2010-05-15 05:04:39 UTC (rev 5607)
@@ -0,0 +1,269 @@
+# -*- 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.
+##
+
+"""
+Wrappers to translate between the APIs in L{txcaldav.icalendarstore} and those
+in L{twistedcaldav}.
+"""
+
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
+
+from twext.python.filepath import CachingFilePath as FilePath
+
+from twext.web2.http import HTTPError, StatusResponse
+from twext.web2 import responsecode
+
+from twistedcaldav.static import CalDAVFile
+
+from txdav.propertystore.base import PropertyName
+
+
+
+class _NewStorePropertiesWrapper(object):
+    """
+    Wrap a new-style property store (a L{txdav.idav.IPropertyStore}) in the old-
+    style interface for compatibility with existing code.
+    """
+
+    # FIXME: UID arguments on everything need to be tested against something.
+    def __init__(self, newPropertyStore):
+        """
+        Initialize an old-style property store from a new one.
+
+        @param newPropertyStore: the new-style property store.
+        @type newPropertyStore: L{txdav.idav.IPropertyStore}
+        """
+        self._newPropertyStore = newPropertyStore
+
+    @classmethod
+    def _convertKey(cls, qname):
+        namespace, name = qname
+        return PropertyName(namespace, name)
+
+
+    # FIXME 'uid' here should be verifying something.
+    def get(self, qname, uid=None):
+        """
+        
+        """
+        try:
+            return self._newPropertyStore[self._convertKey(qname)]
+        except KeyError:
+            raise HTTPError(StatusResponse(
+                    responsecode.NOT_FOUND,
+                    "No such property: {%s}%s" % qname))
+
+
+    def set(self, property, uid=None):
+        """
+        
+        """
+        self._newPropertyStore[self._convertKey(property.qname())] = property
+
+
+    def delete(self, qname, uid=None):
+        """
+        
+        """
+        del self._newPropertyStore[self._convertKey(qname)]
+
+
+    def contains(self, qname, uid=None, cache=True):
+        """
+        
+        """
+        return (self._convertKey(qname) in self._newPropertyStore)
+
+
+    def list(self, uid=None, filterByUID=True, cache=True):
+        """
+        
+        """
+        return [(pname.namespace, pname.name) for pname in
+                self._newPropertyStore.keys()]
+
+
+
+class CalendarCollectionFile(CalDAVFile):
+    """
+    Wrapper around a L{txcaldav.icalendar.ICalendar}.
+    """
+
+    def __init__(self, calendar, home, *args, **kw):
+        """
+        Create a CalendarCollectionFile from a L{txcaldav.icalendar.ICalendar}
+        and the arguments required for L{CalDAVFile}.
+        """
+        super(CalendarCollectionFile, self).__init__(*args, **kw)
+        self._initializeWithCalendar(calendar, home)
+
+
+    def _initializeWithCalendar(self, calendar, home):
+        """
+        Initialize with a calendar.
+
+        @param calendar: the wrapped calendar.
+        @type calendar: L{txcaldav.icalendarstore.ICalendar}
+
+        @param home: the home through which the given calendar was accessed.
+        @type home: L{txcaldav.icalendarstore.ICalendarHome}
+        """
+        self._newStoreCalendar = calendar
+        self._newStoreParentHome = home
+        self._dead_properties = _NewStorePropertiesWrapper(
+            self._newStoreCalendar.properties()
+        )
+
+
+    @classmethod
+    def transform(cls, self, calendar, home):
+        """
+        Transform C{self} into a L{CalendarCollectionFile}.
+        """
+        self.__class__ = cls
+        self._initializeWithCalendar(calendar, home)
+
+
+    def createSimilarFile(self, path):
+        """
+        Create a L{CalendarObjectFile} or L{ProtoCalendarObjectFile} based on a
+        path object.
+        """
+        if not isinstance(path, FilePath):
+            path = FilePath(path)
+
+        newStoreObject = self._newStoreCalendar.calendarObjectWithName(
+            path.basename()
+        )
+
+        if newStoreObject is not None:
+            # FIXME: what about creation in http_PUT?
+            similar = CalendarObjectFile(newStoreObject, path)
+        else:
+            # similar = ProtoCalendarObjectFile(self._newStoreCalendar, path)
+            similar = CalDAVFile(path)
+
+        # FIXME: tests should fail without this:
+        # self.propagateTransaction(similar)
+
+        # Short-circuit stat with information we know to be true at this point
+        if isinstance(path, FilePath) and hasattr(self, "knownChildren"):
+            if path.basename() in self.knownChildren:
+                path.existsCached = True
+                path.isDirCached = False
+
+        #
+        # Override the dead property store
+        #
+        superDeadProperties = similar.deadProperties
+
+        def deadProperties():
+            if not hasattr(similar, "_dead_properties"):
+                similar._dead_properties = self.propertyCollection().propertyStoreForChild(
+                    similar,
+                    superDeadProperties(caching=False)
+                )
+            return similar._dead_properties
+
+        similar.deadProperties = deadProperties
+
+        #
+        # Override DELETE, MOVE
+        #
+        for method in ("DELETE", "MOVE"):
+            method = "http_" + method
+            original = getattr(similar, method)
+
+            @inlineCallbacks
+            def override(request, original=original):
+
+                # Call original method (which is deferred)
+                response = (yield original(request))
+
+                # Wipe the cache
+                similar.deadProperties().flushCache()
+
+                returnValue(response)
+
+            setattr(similar, method, override)
+        self.propagateTransaction(similar)
+        return similar
+
+
+
+class ProtoCalendarCollectionFile(CalDAVFile):
+    """
+    A resource representing a calendar collection which hasn't yet been created.
+    """
+
+    def __init__(self, home, *args, **kw):
+        """
+        A placeholder resource for a calendar collection which does not yet
+        exist, but will become a L{CalendarCollectionFile}.
+
+        @param home: The calendar home which will be this resource's parent,
+            when it exists.
+
+        @type home: L{txcaldav.icalendarstore.ICalendarHome}
+        """
+        self._newStoreParentHome = home
+        super(ProtoCalendarCollectionFile, self).__init__(*args, **kw)
+
+
+    def createSimilarFile(self, path):
+        # FIXME: this is necessary for 
+        # twistedcaldav.test.test_mkcalendar.
+        #     MKCALENDAR.test_make_calendar_no_parent - there should be a more
+        # structured way to refuse creation with a non-existent parent.
+        return CalDAVFile(path)
+
+
+    def createCalendarCollection(self):
+        """
+        Override C{createCalendarCollection} to actually do the work.
+        """
+        d = succeed(responsecode.CREATED)
+
+        calendarName = self.fp.basename()
+        self._newStoreParentHome.createCalendarWithName(calendarName)
+        newStoreCalendar = self._newStoreParentHome.calendarWithName(
+            calendarName
+        )
+        CalendarCollectionFile.transform(
+            self, newStoreCalendar, self._newStoreParentHome
+        )
+        return d
+
+
+
+class CalendarObjectFile(CalDAVFile):
+    """
+    A resource wrapping a calendar object.
+    """
+
+    def __init__(self, calendarObject, *args, **kw):
+        """
+        Construct a L{CalendarObjectFile} from an L{ICalendarObject}.
+
+        @param calendarObject: The storage for the calendar object.
+        @type calendarObject: L{txcaldav.icalendarstore.ICalendarObject}
+        """
+        self._newStoreObject = calendarObject
+        super(CalendarObjectFile, self).__init__(*args, **kw)
+
+
+


Property changes on: CalendarServer/branches/new-store/twistedcaldav/storebridge.py
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: CalendarServer/branches/new-store/twistedcaldav/test/test_wrapping.py
===================================================================
--- CalendarServer/branches/new-store/twistedcaldav/test/test_wrapping.py	2010-05-15 04:55:35 UTC (rev 5606)
+++ CalendarServer/branches/new-store/twistedcaldav/test/test_wrapping.py	2010-05-15 05:04:39 UTC (rev 5607)
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
+
 """
 Tests for the interaction between model-level and protocol-level logic.
 """
@@ -22,6 +23,8 @@
 from twistedcaldav.directory.calendar import uidsResourceName
 from twistedcaldav.ical import Component as VComponent
 
+from twistedcaldav.storebridge import ProtoCalendarCollectionFile
+
 from twistedcaldav.test.util import TestCase
 
 from txcaldav.calendarstore.file import CalendarStore, CalendarHome
@@ -135,7 +138,7 @@
         initialized to match.
         """
         calDavFile = yield self.getResource("calendars/users/wsanchez/frobozz")
-        self.assertIdentical(calDavFile._newStoreCalendar, None)
+        self.assertIsInstance(calDavFile, ProtoCalendarCollectionFile)
         calDavFile.createCalendarCollection()
         self.assertEquals(calDavFile.fp, calDavFile._newStoreCalendar._path)
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100514/963cda4c/attachment-0001.html>


More information about the calendarserver-changes mailing list