Package ldaptor :: Module inmemory
[hide private]
[frames] | no frames]

Source Code for Module ldaptor.inmemory

  1  from zope.interface import implements 
  2  from twisted.internet import defer, error 
  3  from twisted.python.failure import Failure 
  4  from ldaptor import interfaces, entry, entryhelpers 
  5  from ldaptor.protocols.ldap import distinguishedname, ldaperrors, ldifprotocol 
  6   
7 -class LDAPCannotRemoveRootError(ldaperrors.LDAPNamingViolation):
8 """Cannot remove root of LDAP tree"""
9
10 -class ReadOnlyInMemoryLDAPEntry(entry.EditableLDAPEntry, 11 entryhelpers.DiffTreeMixin, 12 entryhelpers.SubtreeFromChildrenMixin, 13 entryhelpers.MatchMixin, 14 entryhelpers.SearchByTreeWalkingMixin, 15 ):
16 implements(interfaces.IConnectedLDAPEntry) 17
18 - def __init__(self, *a, **kw):
19 entry.BaseLDAPEntry.__init__(self, *a, **kw) 20 self._parent = None 21 self._children = []
22
23 - def parent(self):
24 return self._parent
25
26 - def children(self, callback=None):
27 if callback is None: 28 return defer.succeed(self._children[:]) 29 else: 30 for c in self._children: 31 callback(c) 32 return defer.succeed(None)
33
34 - def _lookup(self, dn):
35 if not self.dn.contains(dn): 36 raise ldaperrors.LDAPNoSuchObject(dn) 37 if dn == self.dn: 38 return defer.succeed(self) 39 40 for c in self._children: 41 if c.dn.contains(dn): 42 return c.lookup(dn) 43 44 raise ldaperrors.LDAPNoSuchObject(dn)
45
46 - def lookup(self, dn):
47 return defer.maybeDeferred(self._lookup, dn)
48
49 - def fetch(self, *attributes):
50 return defer.succeed(self)
51
52 - def addChild(self, rdn, attributes):
53 """TODO ugly API. Returns the created entry.""" 54 rdn = distinguishedname.RelativeDistinguishedName(rdn) 55 for c in self._children: 56 if c.dn.split()[0] == rdn: 57 raise ldaperrors.LDAPEntryAlreadyExists, c.dn 58 dn = distinguishedname.DistinguishedName(listOfRDNs= 59 (rdn,) 60 +self.dn.split()) 61 e = ReadOnlyInMemoryLDAPEntry(dn, attributes) 62 e._parent = self 63 self._children.append(e) 64 return e
65
66 - def _delete(self):
67 if self._parent is None: 68 raise LDAPCannotRemoveRootError 69 if self._children: 70 raise ldaperrors.LDAPNotAllowedOnNonLeaf, self.dn 71 return self._parent.deleteChild(self.dn.split()[0])
72
73 - def delete(self):
74 return defer.maybeDeferred(self._delete)
75
76 - def _deleteChild(self, rdn):
77 if not isinstance(rdn, distinguishedname.RelativeDistinguishedName): 78 rdn = distinguishedname.RelativeDistinguishedName(stringValue=rdn) 79 for c in self._children: 80 if c.dn.split()[0] == rdn: 81 self._children.remove(c) 82 return c 83 raise ldaperrors.LDAPNoSuchObject, rdn
84
85 - def deleteChild(self, rdn):
86 return defer.maybeDeferred(self._deleteChild, rdn)
87
88 - def _move(self, newDN):
89 if not isinstance(newDN, distinguishedname.DistinguishedName): 90 newDN = distinguishedname.DistinguishedName(stringValue=newDN) 91 if newDN.up() != self.dn.up(): 92 # climb up the tree to root 93 root = self 94 while root._parent is not None: 95 root = root._parent 96 d = defer.maybeDeferred(root.lookup, newDN.up()) 97 else: 98 d = defer.succeed(None) 99 d.addCallback(self._move2, newDN) 100 return d
101
102 - def _move2(self, newParent, newDN):
103 if newParent is not None: 104 newParent._children.append(self) 105 self._parent._children.remove(self) 106 # remove old RDN attributes 107 for attr in self.dn.split()[0].split(): 108 self[attr.attributeType].remove(attr.value) 109 # add new RDN attributes 110 for attr in newDN.split()[0].split(): 111 # TODO what if the key does not exist? 112 self[attr.attributeType].add(attr.value) 113 self.dn = newDN 114 return self
115
116 - def move(self, newDN):
117 return defer.maybeDeferred(self._move, newDN)
118
119 - def commit(self):
120 return defer.succeed(self)
121
122 -class InMemoryLDIFProtocol(ldifprotocol.LDIF):
123 124 """ 125 Receive LDIF data and gather results into an ReadOnlyInMemoryLDAPEntry. 126 127 You can override lookupFailed and addFailed to provide smarter 128 error handling. They are called as Deferred errbacks; returning 129 the reason causes error to pass onward and abort the whole 130 operation. Returning None from lookupFailed skips that entry, but 131 continues loading. 132 133 When the full LDIF data has been read, the completed Deferred will 134 trigger. 135 """ 136
137 - def __init__(self):
138 self.db = None #do not access this via db, just to make sure you respect the ordering 139 self._deferred = defer.Deferred() 140 self.completed = defer.Deferred()
141
142 - def _addEntry(self, db, entry):
143 d = db.lookup(entry.dn.up()) 144 d.addErrback(self.lookupFailed, entry) 145 146 def _add(parent, entry): 147 if parent is not None: 148 parent.addChild(rdn=entry.dn.split()[0], 149 attributes=entry)
150 d.addCallback(_add, entry) 151 d.addErrback(self.addFailed, entry) 152 153 def _passDB(_, db): 154 return db
155 d.addCallback(_passDB, db) 156 return d 157
158 - def gotEntry(self, entry):
159 if self.db is None: 160 # first entry, create the db, prepare to process the rest 161 self.db = ReadOnlyInMemoryLDAPEntry( 162 dn=entry.dn, 163 attributes=entry) 164 self._deferred.callback(self.db) 165 else: 166 self._deferred.addCallback(self._addEntry, entry)
167
168 - def lookupFailed(self, reason, entry):
169 return reason # pass the error (abort) by default
170
171 - def addFailed(self, reason, entry):
172 return reason # pass the error (abort) by default
173
174 - def connectionLost(self, reason):
175 super(InMemoryLDIFProtocol, self).connectionLost(reason) 176 if not reason.check(error.ConnectionDone): 177 self._deferred.addCallback(lambda db: reason) 178 else: 179 self._deferred.chainDeferred(self.completed) 180 181 del self._deferred # invalidate it to flush out bugs
182
183 -def fromLDIFFile(f):
184 """Read LDIF data from a file.""" 185 186 p = InMemoryLDIFProtocol() 187 while 1: 188 data = f.read() 189 if not data: 190 break 191 p.dataReceived(data) 192 p.connectionLost(Failure(error.ConnectionDone())) 193 194 return p.completed
195