class SQLModTime(SQLGatewayBase): """SQL object mod time gateway""" __implements__ = SQLGatewayBase.__implements__ schema = ColumnSchema('mtime', 'int') # second table_name = 'mtime' table_schema = RowSequenceSchema() table_schema.add('mtime', 'long', 0) def load(self, event): table = self.get_table(event) items = table.select(self.column_names, oid=event.oid) if items: state = long(items[0][0]) else: state = 0L return state, state def store(self, event, state): state = long(state) table = self.get_table(event) data = (state, ) table.set_one(event.oid, self.column_names, data, event.is_new) return state
class SQLClassification(SQLGatewayBase): __implements__ = SQLGatewayBase.__implements__ schema = ColumnSchema('classification', 'classification') table_name = 'classification' table_schema = RowSequenceSchema() table_schema.add('class_name', 'string', 0) table_schema.add('mapper_name', 'string', 0) def load(self, event): table = self.get_table(event) rows = table.select(self.column_names, oid=event.oid) classification = {} if rows: rec = rows[0] if rec[0]: classification['class_name'] = rec[0] if rec[1]: classification['mapper_name'] = rec[1] else: raise KeyError(event.oid) return classification, rec def store(self, event, classification): conn = self.get_connection(event) table = self.get_table(event) row = (classification.get('class_name', ''), classification.get('mapper_name', '')) try: table.set_one(event.oid, self.column_names, row, event.is_new) except conn.module.DatabaseError: raise OIDConflictError(event.oid) return row
class IdAttribute: """Zope 2 id attribute.""" __implements__ = ISerializer schema = ColumnSchema('id', 'string') def can_serialize(self, obj): return 1 def _get_attr_name_for(self, obj): if isinstance(obj, Item_w__name__): return '__name__' else: return 'id' def serialize(self, event): obj = event.obj attrname = self._get_attr_name_for(obj) id = getattr(obj, attrname) if not id: raise SerializationError('ID of %r is %r' % (obj, id)) event.serialized(attrname, id, 1) return id def deserialize(self, event, state): obj = event.obj attrname = self._get_attr_name_for(obj) setattr(obj, attrname, state) # Allow references under either attribute name. event.deserialized('id', state) event.deserialized('__name__', state)
class FilePData: """Serializer of the 'data' attribute of OFS.File and OFS.Image""" __implements__ = ISerializer schema = ColumnSchema('data', 'string') def can_serialize(self, object): return isinstance(object, File) def serialize(self, event): obj = event.obj event.serialized('data', obj.data, 1) event.ignore(('size', 'width', 'height')) return str(obj.data) def deserialize(self, event, state): obj = event.obj data, size = obj._read_data(state) if not obj.__dict__.get('content_type'): # Guess the content type. content_type = obj._get_content_type(state, data, obj.__name__) else: # The properties serializer is authoritative. Defer to it. content_type = None obj.update_data(data, content_type, size) event.deserialized('data', obj.data)
class FSFileData(FSGatewayBase): """File data gateway, where data is a string. """ __implements__ = IGateway schema = ColumnSchema('data', 'string') def __init__(self, text=0, conn_name='fs'): if text == 'text': text = 1 elif text == 'binary': text = 0 self.text = text FSGatewayBase.__init__(self, conn_name) def load(self, event): c = self.get_connection(event) assert c.read_node_type(event.oid) == 'f' state = c.read_data(event.oid, as_text=self.text) return state, state def store(self, event, state): if not isinstance(state, StringType): raise ValueError('Not a string: %s' % repr(state)) c = self.get_connection(event) c.write_node_type(event.oid, 'f') c.write_data(event.oid, state, as_text=self.text) return state
class SQLItemId(SQLGatewayBase): """SQL item ID gateway. Piggybacks SQLFolderItems for init and store. Makes the assumption that the item is stored in only one place. """ __implements__ = SQLGatewayBase.__implements__ schema = ColumnSchema('id', 'string') table_name = 'folder_items' table_schema = RowSequenceSchema() table_schema.add('child_oid', 'int', 1) table_schema.add('name', 'string', 0) def init(self, event): pass def load(self, event): table = self.get_table(event) rows = table.select(('name', ), child_oid=event.oid) if len(rows) >= 1: name = rows[0][0] # Accept only the first result else: name = None # Disable conflict checking by returning None as the hash value. return name, None def store(self, event, state): return None
class SQLObjectData(SQLGatewayBase): """SQL object data gateway""" __implements__ = SQLGatewayBase.__implements__ schema = ColumnSchema('data', 'string') table_name = 'object_data' table_schema = RowSequenceSchema() table_schema.add('data', 'blob', 0) def load(self, event): table = self.get_table(event) firstcol = self.column_names[:1] items = table.select(firstcol, oid=event.oid) if items: state = str(items[0][0]) else: state = '' return state, state def store(self, event, state): conn = self.get_connection(event) table = self.get_table(event) firstcol = self.column_names[:1] data = (state, ) table.set_one(event.oid, firstcol, data, event.is_new) return state
class ModTimeAttribute: """Sets the _p_mtime attribute. XXX Due to a ZODB limitation, this class has to set the _p_mtime by setting _p_serial. """ __implements__ = ISerializer schema = ColumnSchema('mtime', 'int') def can_serialize(self, obj): return is_persistent(obj) def _set_time(self, obj, t): """Sets the last modification time of a Persistent obj to float t. """ args = time.gmtime(t)[:5] + (t%60,) obj._p_serial = repr(TimeStamp(*args)) def serialize(self, event): now = long(time.time()) if event.obj._p_changed: # Indicate that this object just changed. Note that the time # is a guess. self._set_time(event.obj, now) return now def deserialize(self, event, state): self._set_time(event.obj, state)
class SQLSecurityAttributes(SQLGatewayBase): """SQL security attribute storage""" __implements__ = SQLGatewayBase.__implements__ schema = RowSequenceSchema() schema.add('declaration_type', 'string') schema.add('role', 'string') schema.add('permission', 'string') schema.add('username', 'string') table_name = 'security' oid_columns = [ColumnSchema('oid', 'int', 0)] # Don't create a primary key def load(self, event): table = self.get_table(event) items = table.select(self.column_names, oid=event.oid) items.sort() return items, tuple(items) def store(self, event, state): table = self.get_table(event) table.set_many(event.oid, (), self.column_names, state) state = list(state) state.sort() return tuple(state)
class SQLGatewayBase: """SQL gateway base class""" __implements__ = IGateway, IDatabaseInitializer # override these in subclasses table_name = None schema = None table_schema = None oid_columns = [ColumnSchema('oid', 'int', 1)] def __init__(self, conn_name='db'): self.conn_name = conn_name if self.table_schema is None: if self.schema is not None: self.table_schema = self.schema else: self.table_schema = RowSequenceSchema() self.column_names = [f.name for f in self.table_schema.get_columns()] def get_connection(self, event): return event.connections[self.conn_name] def get_table(self, event): c = event.connections[self.conn_name] return c.get_table(self.table_name) def create(self, event): self.get_table(event).create() def init(self, event): conn = self.get_connection(event) assert IRDBMSConnection.isImplementedBy(conn) all = RowSequenceSchema( self.oid_columns + self.table_schema.get_columns()) table = conn.define_table(self.table_name, all) if conn.exists(self.table_name, 'table'): if IDatabaseInitEvent.isImplementedBy(event) and event.clear_all: table.delete_rows() else: table.create() def load(self, event): raise NotImplementedError, "abstract method" def store(self, event, obj): raise NotImplementedError, "abstract method" def get_sources(self, event): return None
class FSModTime(FSGatewayBase): """Reads the modification time of a file.""" __implements__ = IGateway schema = ColumnSchema('mtime', 'int') def load(self, event): fs_conn = self.get_connection(event) state = long(fs_conn.read_mod_time(event.oid)) return state, None # Use None as the hash (see store()) def store(self, event, state): # Under normal circumstances, there is no need to change the mod # time of a file. Ignore by returning None as the hash. return None
class FSClassificationAnnotation(FSGatewayBase): """Gateway for storing classification data.""" __implements__ = IGateway schema = ColumnSchema('classification', 'classification') def load(self, event): fs_conn = self.get_connection(event) oid = event.oid classification = {'node_type': fs_conn.read_node_type(oid)} text = fs_conn.read_annotation(oid, 'classification', '') if text: lines = text.split('\n') for line in lines: if '=' in line: k, v = line.split('=', 1) classification[k.strip()] = v.strip() classification['extension'] = fs_conn.read_extension(oid) classification['subpath'] = fs_conn.get_subpath(oid) return classification, text.strip() def store(self, event, state): # state is a classification fs_conn = self.get_connection(event) oid = event.oid if event.is_new: # Don't overwrite existing data try: fs_conn.read_node_type(oid) except LoadError: # Nothing exists yet. pass else: # Something exists. Don't overwrite it. raise OIDConflictError(oid) items = state.items() items.sort() text = [] for k, v in items: if k == 'extension': fs_conn.suggest_extension(oid, v) else: text.append('%s=%s' % (k, v)) text = '\n'.join(text) fs_conn.write_annotation(oid, 'classification', text) return text.strip()
class FSAutoId(FSGatewayBase): """Automatic ID gateway based on the object name in the primary parent. """ __implements__ = IGateway schema = ColumnSchema('id', 'string') def load(self, event): id = self.get_connection(event).read_object_name(event.oid) # Disable conflict checking by returning None as the hash value. return id, None def store(self, event, state): # Ignore. return None def get_sources(self, event): fs_conn = self.get_connection(event) return fs_conn.get_sources(event.oid)
class ZSQLMethodSerializer: """Serializer for ZSQLMethods. ZSQLMethodSerializer serializes using the same representation as FTP or WebDAV. All computable attributes like compiled code are dropped. """ __implements__ = ISerializer schema = ColumnSchema('data', 'string') params_re = re.compile(r'\s*<params>(.*)</params>\s*\n', re.I | re.S) def can_serialize(self, obj): return isinstance(obj, SQL) def serialize(self, event): data = event.obj.document_src() event.ignore(('_arg', 'template', 'arguments_src', 'src')) return data def deserialize(self, event, state): obj = event.obj assert isinstance(state, StringType) assert isinstance(obj, SQL) body = state m = self.params_re.match(body) if m: obj.arguments_src = m.group(1) body = body[m.end():] else: obj.arguments_src = '' obj._arg = parse(obj.arguments_src) obj.src = body obj.template = obj.template_class(body) obj.template.cook() obj._v_cache = ({}, Bucket()) if not hasattr(obj, 'connection_id'): obj.connection_id = ''
class PythonScriptSerializer: """Serializer for PythonScripts. PythonScriptSerializer serializes using the same representation as FTP or WebDAV. All computable attributes like compiled code are dropped. """ __implements__ = ISerializer schema = ColumnSchema('data', 'string') def can_serialize(self, obj): return isinstance(obj, PythonScript) def serialize(self, event): assert isinstance(event.obj, PythonScript) data = event.obj.read() assert isinstance(data, StringType) event.ignore(( 'title', '_params', '_body', '_bind_names', 'warnings', 'errors', '_code', 'Python_magic', 'Script_magic', 'func_defaults', 'func_code', 'co_varnames', 'co_argcount', )) return data def deserialize(self, event, state): obj = event.obj assert isinstance(state, StringType) assert isinstance(event.obj, PythonScript) # Circumvent proxy role checking while deserializing the script. obj._validateProxy = lambda: 0 try: obj.write(state) obj._makeFunction() finally: # Remove the proxy circumvention del obj._validateProxy
class FSAnnotationData(FSGatewayBase): """Text to filesystem property annotation gateway.""" __implements__ = IGateway schema = ColumnSchema('data', 'string') def __init__(self, annotation, conn_name='fs'): self.annotation = str(annotation) FSGatewayBase.__init__(self, conn_name) def load(self, event): fs_conn = self.get_connection(event) state = fs_conn.read_annotation(event.oid, self.annotation, '').strip() return state, state def store(self, event, state): if not isinstance(state, StringType): raise ValueError('Not a string: %s' % repr(state)) state = state.strip() if state: fs_conn = self.get_connection(event) fs_conn.write_annotation(event.oid, self.annotation, state) return state
class PersistentMappingSerializer: """(de)serializer of a persistent mapping that uses string keys. Serializes both references and second-class persistent objects. Because of this flexibility, the schema is a little complex. """ __implements__ = ISerializer # This schema includes both a list of items that are references to # persistent objects and a pickle containing items that are not # references. schema1 = RowSequenceSchema() schema1.add('key', 'string', 1) schema1.add('oid', 'string') schema1.add('classification', 'classification') schema2 = ColumnSchema('data', 'string') schema = {'references': schema1, 'others': schema2} def can_serialize(self, obj): return isinstance(obj, PersistentMapping) def serialize(self, event): assert self.can_serialize(event.obj) refs = [] others = {} for key, value in event.obj.items(): if is_persistent(value): oid = event.obj_db.identify(value) if oid is None: oid = event.obj_db.new_oid() event.referenced(key, value, False, oid) # No need to pass classification. refs.append((key, oid, None)) else: event.serialized(key, value, False) others[key] = value event.ignore(('data', '_container')) if others: # Encode as a sorted list to preserve order. others_list = others.items() others_list.sort() s = encode_to_text(dumps(others_list, 1), others.keys()) else: s = '' return {'references': refs, 'others': s} def deserialize(self, event, state): assert self.can_serialize(event.obj) data_dict = {} s = state['others'] if s: s = decode_from_text(s) if s: data = loads(s) if hasattr(data, 'items'): # Stored as a dictionary data_list = data.items() data_dict = data else: # Stored as a sequence of tuples data_list = data for key, value in data: data_dict[key] = value for key, value in data_list: event.deserialized(key, value) for (key, oid, classification) in state['references']: value = event.resolve(key, oid, classification) data_dict[key] = value event.obj.__init__(data_dict)
class RemainingState: """(De)serializes the remaining state of a Persistent object""" __implements__ = ISerializer schema = ColumnSchema('data', 'string') def can_serialize(self, obj): return is_persistent(obj) def serialize(self, event): assert IFullSerializationEvent.isImplementedBy(event) assert isinstance(event.obj, Persistent) # Allow pickling of cyclic references to the object. event.serialized('self', event.obj, False) # Ignore previously serialized attributes state = event.obj.__dict__.copy() for key in state.keys(): if key.startswith('_v_'): del state[key] for attrname in event.get_seralized_attributes(): if state.has_key(attrname): del state[attrname] if not state: # No data needs to be stored return '' outfile = StringIO() p = Pickler(outfile, 1) # Binary pickle unmanaged = [] def persistent_id(ob, identify_internal=event.identify_internal, unmanaged=unmanaged): ref = identify_internal(ob) if ref is None: if hasattr(ob, '_p_oid'): # Persistent objects that end up in the remainder # are unmanaged. Tell ZODB about them so that # ZODB can deal with them specially. unmanaged.append(ob) return ref # Preserve order to a reasonable extent by storing a list # instead of a dictionary. state_list = state.items() state_list.sort() p.persistent_id = persistent_id try: p.dump(state_list) except UnpickleableError, exc: # Try to reveal which attribute is unpickleable. attrname = None attrvalue = None for key, value in state_list: del unmanaged[:] outfile.seek(0) outfile.truncate() p = Pickler(outfile) p.persistent_id = persistent_id try: p.dump(value) except UnpickleableError: attrname = key attrvalue = value break if attrname is not None: # Provide a more informative exception. if os.environ.get('APE_TRACE_UNPICKLEABLE'): # Provide an opportunity to examine # the "attrvalue" attribute. import pdb pdb.set_trace() raise RuntimeError( 'Unable to pickle the %s attribute, %s, ' 'of %s at %s. %s.' % ( repr(attrname), repr(attrvalue), repr(event.obj), repr(event.oid), str(exc))) else: # Couldn't help. raise p.persistent_id = lambda ob: None # Stop recording references p.dump(unmanaged) event.upos.extend(unmanaged) s = outfile.getvalue() return encode_to_text(s, state.keys(), len(unmanaged))