Skip to content
Snippets Groups Projects
Commit 19a484ff authored by Julian's avatar Julian
Browse files

Some restructuring

parent 245aba18
No related branches found
No related tags found
No related merge requests found
...@@ -15,6 +15,9 @@ class State: ...@@ -15,6 +15,9 @@ class State:
return State(self.status, deepcopy(self.attributes)) return State(self.status, deepcopy(self.attributes))
class Operation: class Operation:
def __init__(self, obj):
self.obj = obj
def apply(self, state): def apply(self, state):
raise NotImplemented() raise NotImplemented()
...@@ -25,7 +28,8 @@ class Operation: ...@@ -25,7 +28,8 @@ class Operation:
return False return False
class AddOperation(Operation): class AddOperation(Operation):
def __init__(self, attributes, ldap_object_classes): def __init__(self, obj, attributes, ldap_object_classes):
super().__init__(obj)
self.attributes = deepcopy(attributes) self.attributes = deepcopy(attributes)
self.ldap_object_classes = ldap_object_classes self.ldap_object_classes = ldap_object_classes
...@@ -33,8 +37,8 @@ class AddOperation(Operation): ...@@ -33,8 +37,8 @@ class AddOperation(Operation):
state.status = Status.ADDED state.status = Status.ADDED
state.attributes = self.attributes state.attributes = self.attributes
def execute(self, dn, conn): def execute(self, conn):
success = conn.add(dn, self.ldap_object_classes, self.attributes) success = conn.add(self.obj.dn, self.ldap_object_classes, self.attributes)
if not success: if not success:
raise LDAPCommitError() raise LDAPCommitError()
...@@ -42,13 +46,14 @@ class DeleteOperation(Operation): ...@@ -42,13 +46,14 @@ class DeleteOperation(Operation):
def apply(self, state): def apply(self, state):
state.status = Status.DELETED state.status = Status.DELETED
def execute(self, dn, conn): def execute(self, conn):
success = conn.delete(dn) success = conn.delete(self.obj.dn)
if not success: if not success:
raise LDAPCommitError() raise LDAPCommitError()
class ModifyOperation(Operation): class ModifyOperation(Operation):
def __init__(self, changes): def __init__(self, obj, changes):
super().__init__(obj)
self.changes = deepcopy(changes) self.changes = deepcopy(changes)
def apply(self, state): def apply(self, state):
...@@ -62,8 +67,8 @@ class ModifyOperation(Operation): ...@@ -62,8 +67,8 @@ class ModifyOperation(Operation):
for value in values: for value in values:
state.attributes[attr].remove(value) state.attributes[attr].remove(value)
def execute(self, dn, conn): def execute(self, conn):
success = conn.modify(dn, self.changes) success = conn.modify(self.obj.dn, self.changes)
if not success: if not success:
raise LDAPCommitError() raise LDAPCommitError()
...@@ -72,27 +77,41 @@ class Session: ...@@ -72,27 +77,41 @@ class Session:
def __init__(self): def __init__(self):
self.__objects = {} self.__objects = {}
self.__deleted_objects = {}
self.__operations = [] self.__operations = []
def record(self, obj, oper): # Never called directly!
if not self.__operations or self.__operations[0][0] != obj or not self.__operations[0][1].extend(oper): def record(self, oper):
self.__operations.append((obj, oper)) if isinstance(oper, AddOperation):
if oper.obj.ldap_state.session == self:
return
if oper.obj.ldap_state.session is not None:
raise Exception()
if oper.obj.dn in self.__objects:
raise Exception()
self.__objects[oper.obj.dn] = oper.obj
elif isinstance(oper, DeleteOperation):
if oper.obj.ldap_state.session is None:
return
if oper.obj.ldap_state.session != self:
raise Exception()
if oper.obj.dn not in self.__objects:
raise Exception()
if oper.obj.dn in self.__deleted_objects:
raise Exception()
self.__deleted_objects[oper.obj.dn] = oper.obj
del self.__objects[oper.obj.dn]
else:
if oper.obj.ldap_state.session is None:
return
if not self.__operations or not self.__operations[-1].extend(oper):
self.__operations.append(oper)
# TODO: maybe move the implementation to SessionObjectState?
def add(self, obj): def add(self, obj):
if obj.ldap_state.current.status != Status.NEW: obj.ldap_state.add(self)
return
oper = AddOperation(obj.ldap_state.current.attributes, obj.ldap_object_classes)
oper.apply(obj.ldap_state.current)
self.__operations.append((obj, oper))
# TODO: maybe move the implementation to SessionObjectState?
def delete(self, obj): def delete(self, obj):
if obj.ldap_state.current.status != Status.ADDED: obj.ldap_state.delete()
return
oper = DeleteOperation()
oper.apply(obj.ldap_state.current)
self.__operations.append((obj, oper))
def commit(self): def commit(self):
conn = self.mapper.connect() conn = self.mapper.connect()
...@@ -103,7 +122,6 @@ class Session: ...@@ -103,7 +122,6 @@ class Session:
except e: except e:
self.__operations.insert(0, (obj, oper)) self.__operations.insert(0, (obj, oper))
raise e raise e
oper.apply(obj.ldap_state.committed)
def rollback(self): def rollback(self):
while self.__operations: while self.__operations:
...@@ -146,32 +164,49 @@ class Session: ...@@ -146,32 +164,49 @@ class Session:
class SessionObjectState: class SessionObjectState:
def __init__(self, obj, response=None): def __init__(self, obj, response=None):
self.obj = obj self.obj = obj
self.session = obj.ldap_mapper.session self.session = None
if response is not None: if response is not None:
self.commited = State() self.commited = State()
else: else:
self.commited = State(Status.ADDED, response['attributes']) self.commited = State(Status.ADDED, response['attributes'])
self.current = self.commited.copy() self.current = self.commited.copy()
def add(self, session):
if self.session is not None:
return
# TODO: call hook functions
oper = AddOperation(self.current.attributes, self.obj.ldap_object_classes)
self.session.record(self.obj, oper)
self.session = session
oper.apply(self.current)
def delete(self):
if self.session is None:
return
oper = DeleteOperation()
self.session.record(self.obj, oper)
self.session = None
oper.apply(self.current)
def getattr(self, name): def getattr(self, name):
return self.current.attributes.get(name, []) return self.current.attributes.get(name, [])
def setattr(self, name, values): def setattr(self, name, values):
oper = ModifyOperation({name: [(MODIFY_REPLACE, [values])]}) oper = ModifyOperation({name: [(MODIFY_REPLACE, [values])]})
if self.current.status == Status.ADDED: if self.session is not None:
self.session.record(self.obj, oper) self.session.record(self.obj, oper)
oper.apply(self.current) oper.apply(self.current)
def attr_append(self, name, value): def attr_append(self, name, value):
oper = ModifyOperation({name: [(MODIFY_ADD, [value])]}) oper = ModifyOperation({name: [(MODIFY_ADD, [value])]})
if self.current.status == Status.ADDED: if self.session is not None:
self.session.record(self.obj, oper) self.session.record(self.obj, oper)
oper.apply(self.current) oper.apply(self.current)
def attr_remove(self, name, value): def attr_remove(self, name, value):
# TODO: how does LDAP handle MODIFY_DELETE ops with non-existant values? # TODO: how does LDAP handle MODIFY_DELETE ops with non-existant values?
oper = ModifyOperation({name: [(MODIFY_DELETE, [value])]}) oper = ModifyOperation({name: [(MODIFY_DELETE, [value])]})
if self.current.status == Status.ADDED: if self.session is not None:
self.session.record(self.obj, oper) self.session.record(self.obj, oper)
oper.apply(self.current) oper.apply(self.current)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment