indexing description: "Handles advertisements cache" author: "Beat Strasser " date: "$Date$" revision: "$Revision$" class P2P_CACHE_MANAGER inherit KL_SHARED_FILE_SYSTEM export {NONE} all end create make feature {NONE} -- Initialization make (a_path: STRING; a_logger: L4E_LOGGER) is -- Create manager instance for advertisement cache with given `a_path' require Path_valid: a_path /= Void local a_unix_file_system: KL_UNIX_FILE_SYSTEM do logger := a_logger -- detect directory separator for current file system a_unix_file_system ?= file_system if a_unix_file_system /= Void then dir := a_unix_file_system.directory_separator.out else dir := {KL_WINDOWS_FILE_SYSTEM}.directory_separator.out end logger.debugging ("cache_manager: Detected file system directory separator: " + dir) -- make sure given `a_path' is correct path in current file system if a_path.has ({KL_WINDOWS_FILE_SYSTEM}.directory_separator) then repository_path := file_system.pathname_from_file_system (a_path, windows_file_system) else repository_path := file_system.pathname_from_file_system (a_path, unix_file_system) end repository_path := file_system.absolute_pathname (repository_path) -- check path has_failed := not file_system.directory_exists (repository_path) -- initialize cache structure if not has_failed then check_cache_structure else repository_path := Void end end feature -- Status report has_failed: BOOLEAN -- Has last read or write operation failed? feature -- Access repository_path: STRING -- Path where advertisement cache resists has_configuration_advertisement: BOOLEAN is -- Is platform configuration advertisement in cache? require Repository_valid: repository_path /= Void do Result := file_exists (fn_configuration) end configuration_advertisement: P2P_CONFIGURATION_ADVERTISEMENT is -- Cached platform configuration advertisement require Repository_valid: repository_path /= Void local content: STRING do content := read_from_file (fn_configuration) if content /= Void and not content.is_empty then create Result.parse_from_string (content) if not Result.is_valid then remove_configuration_advertisement Result := Void end end ensure Result_valid: Result /= Void implies Result.is_valid end has_peergroup_advertisement (an_id: P2P_PEERGROUP_ID): BOOLEAN is -- Is peer group advertisement in cache? require Repository_valid: repository_path /= Void Id_valid: an_id /= Void and an_id.is_valid do Result := file_exists (fn_peergroup (an_id)) end peergroup_advertisement (an_id: P2P_PEERGROUP_ID): P2P_PEERGROUP_ADVERTISEMENT is -- Cached peer group advertisement with given `an_id' require Repository_valid: repository_path /= Void Id_valid: an_id /= Void and an_id.is_valid local content: STRING do content := read_from_file (fn_peergroup (an_id)) if content /= Void and not content.is_empty then create Result.parse_from_string (content) if not Result.is_valid then remove_peergroup_advertisement (an_id) Result := Void end end ensure Result_valid: Result /= Void implies Result.is_valid end has_peer_advertisement (a_group_id: P2P_PEERGROUP_ID; an_id: P2P_PEER_ID): BOOLEAN is -- Is peer advertisement in cache? require Repository_valid: repository_path /= Void Group_id_valid: a_group_id /= Void and a_group_id.is_valid Id_valid: an_id /= Void and an_id.is_valid do Result := file_exists (fn_peer (a_group_id, an_id)) end peer_advertisement (a_group_id: P2P_PEERGROUP_ID; an_id: P2P_PEER_ID): P2P_PEER_ADVERTISEMENT is -- Cached peer advertisement with given `an_id' in given `group' require Repository_valid: repository_path /= Void Group_id_valid: a_group_id /= Void and a_group_id.is_valid Id_valid: an_id /= Void and an_id.is_valid local content: STRING do content := read_from_file (fn_peer (a_group_id, an_id)) if content /= Void and not content.is_empty then create Result.parse_from_string (content) if not Result.is_valid then remove_peer_advertisement (a_group_id, an_id) Result := Void end end ensure Result_valid: Result /= Void implies Result.is_valid end has_module_implementation_advertisement (an_id: P2P_MODULE_SPECIFICATION_ID): BOOLEAN is -- Is module implementation advertisement in cache? require Repository_valid: repository_path /= Void Id_valid: an_id /= Void and an_id.is_valid do Result := file_exists (fn_mia (an_id)) end module_implementation_advertisement (an_id: P2P_MODULE_SPECIFICATION_ID): P2P_MODULE_IMPLEMENTATION_ADVERTISEMENT is -- Cached module implementation advertisement with given `an_id' require Repository_valid: repository_path /= Void Id_valid: an_id /= Void and an_id.is_valid local content: STRING do content := read_from_file (fn_mia (an_id)) if content /= Void and not content.is_empty then create Result.parse_from_string (content) if not Result.is_valid then remove_module_implementation_advertisement (an_id) Result := Void end end ensure Result_valid: Result /= Void implies Result.is_valid end feature -- Store store_configuration_advertisement (adv: P2P_CONFIGURATION_ADVERTISEMENT) is -- Store given configuration advertisement in cache require Repository_valid: repository_path /= Void Advertisement_valid: adv /= Void and adv.is_valid do write_to_file (adv.out, fn_configuration) end store_peergroup_advertisement (adv: P2P_PEERGROUP_ADVERTISEMENT) is -- Store given peer group advertisement in cache require Repository_valid: repository_path /= Void Advertisement_valid: adv /= Void and adv.is_valid do check_cache_structure_for_group (adv.group_id) write_to_file (adv.out, fn_peergroup (adv.group_id)) end store_peer_advertisement (adv: P2P_PEER_ADVERTISEMENT) is -- Store given peer advertisement in cache require Repository_valid: repository_path /= Void Advertisement_valid: adv /= Void and adv.is_valid do check_cache_structure_for_group (adv.group_id) write_to_file (adv.out, fn_peer (adv.group_id, adv.peer_id)) end store_module_implementation_advertisement (adv: P2P_MODULE_IMPLEMENTATION_ADVERTISEMENT) is -- Store given module implementation advertisement in cache require Repository_valid: repository_path /= Void Advertisement_valid: adv /= Void and adv.is_valid do check_cache_structure write_to_file (adv.out, fn_mia (adv.specification_id)) end feature -- Removal flush_entire_repository is -- Remove entire cache content require Repository_valid: repository_path /= Void local failed: BOOLEAN do if not failed then file_system.recursive_delete_directory (repository_path) file_system.create_directory (repository_path) end has_failed := failed rescue failed := True retry end remove_configuration_advertisement is -- Remove configuration advertisement require Repository_valid: repository_path /= Void do remove_file (fn_configuration) end remove_peergroup_advertisement (an_id: P2P_PEERGROUP_ID) is -- Remove peer group advertisement require Repository_valid: repository_path /= Void Id_valid: an_id /= Void and an_id.is_valid do remove_file (fn_peergroup (an_id)) end remove_peer_advertisement (a_group_id: P2P_PEERGROUP_ID; an_id: P2P_PEER_ID) is -- Remove peer advertisement require Repository_valid: repository_path /= Void Group_id_valid: a_group_id /= Void and a_group_id.is_valid Id_valid: an_id /= Void and an_id.is_valid do remove_file (fn_peer (a_group_id, an_id)) end remove_module_implementation_advertisement (an_id: P2P_MODULE_SPECIFICATION_ID) is -- Remove module implementation advertisement require Repository_valid: repository_path /= Void Id_valid: an_id /= Void and an_id.is_valid do remove_file (fn_mia (an_id)) end feature {NONE} -- Implementation dir: STRING Ext: STRING is ".xml" Platform_config: STRING is "PlatformConfig" Peergroup: STRING is "PeerGroup" Peers: STRING is "Peers" Modules: STRING is "Modules" logger: L4E_LOGGER read_from_file (a_path: STRING): STRING is -- Read string from file identified by `a_path' (relative to `repository_path') require Repository_valid: repository_path /= Void Path_valid: a_path /= Void local file_name: STRING file: PLAIN_TEXT_FILE failed: BOOLEAN do file_name := file_system.pathname (repository_path, a_path) failed := failed or not file_system.file_exists (file_name) if not failed then create file.make_open_read (file_name) file.read_stream (file.count) Result := file.last_string file.close end has_failed := failed rescue failed := True logger.debugging ("cache_manager: Error reading from file: " + a_path) retry end write_to_file (content, a_path: STRING) is -- Write `content' to file identified by given `a_path' (relative to `repository_path') require Repository_valid: repository_path /= Void Content_valid: content /= Void and not content.is_empty Path_valid: a_path /= Void local file: PLAIN_TEXT_FILE failed: BOOLEAN do if not failed then create file.make_open_write (file_system.pathname (repository_path, a_path)) file.put_string (content) file.close end has_failed := failed rescue failed := True logger.debugging ("cache_manager: Error writing to file: " + a_path) retry end remove_file (a_path: STRING) is -- Remove file with given `a_path' require Repository_valid: repository_path /= Void Path_valid: a_path /= Void local failed: BOOLEAN do if not failed then file_system.delete_file (file_system.pathname (repository_path, a_path)) end has_failed := failed rescue failed := True logger.debugging ("cache_manager: Error removing file: " + a_path) retry end file_exists (a_path: STRING): BOOLEAN is -- Does file with given `a_path' exist? require Repository_valid: repository_path /= Void Path_valid: a_path /= Void local failed: BOOLEAN do if not failed then Result := file_system.file_exists (file_system.pathname (repository_path, a_path)) end has_failed := failed rescue failed := True logger.debugging ("cache_manager: Error checking for file existence, file: " + a_path) retry end check_cache_structure is -- Make sure general cache structure is ok require Repository_valid: repository_path /= Void local failed: BOOLEAN do if not failed then -- modules/ file_system.create_directory (file_system.pathname (repository_path, modules)) end has_failed := failed rescue failed := True logger.debugging ("cache_manager: Error checking general cache structure") retry end check_cache_structure_for_group (a_group_id: P2P_PEERGROUP_ID) is -- Make sure general cache structure and for `a_group_id' is ok require Repository_valid: repository_path /= Void Group_id_valid: a_group_id /= Void and a_group_id.is_valid local failed: BOOLEAN do if not failed then check_cache_structure -- [peergroupid]/ file_system.create_directory (file_system.pathname (repository_path, simplify (a_group_id.out))) -- [peergroupid]/peers file_system.create_directory (file_system.pathname (repository_path, simplify (a_group_id.out) + dir + peers)) end has_failed := failed rescue failed := True logger.debugging ("cache_manager: Error checking cache structure, group: " + a_group_id.out) retry end simplify (in: STRING): STRING is -- Simplify a string require Input_valid: in /= Void do Result := in.twin if Result.substring (1, 4).is_equal ("urn:") then Result.remove_head (4) end ensure Result_set: Result /= Void end fn_configuration: STRING is -- Relative file path of configuration advertisement do Result := platform_config + ext end fn_peergroup (an_id: P2P_PEERGROUP_ID): STRING is -- Relative file path of peer group advertisement require Id_valid: an_id /= Void and an_id.is_valid do Result := simplify (an_id.out) + dir + peergroup + ext end fn_peer (a_group_id: P2P_PEERGROUP_ID; an_id: P2P_PEER_ID): STRING is -- Relative file path of peer advertisement require Group_id_valid: a_group_id /= Void and a_group_id.is_valid Id_valid: an_id /= Void and an_id.is_valid do Result := simplify (a_group_id.out) + dir + peers + dir + simplify (an_id.out) + ext end fn_mia (an_id: P2P_MODULE_SPECIFICATION_ID): STRING is -- Relative file path of module implementation advertisement require Id_valid: an_id /= Void and an_id.is_valid do Result := modules + dir + simplify (an_id.out) + ext end end