indexing description: "Endpoint message elements container" license: "MIT license (see ../../license.txt)" author: "Beat Strasser " date: "$Date$" revision: "$Revision$" class P2P_MESSAGE inherit ANY redefine out end create make feature {NONE} -- Initialization make is -- Create message local string_equality_tester: KL_EQUALITY_TESTER [STRING] do create namespaces.make (initial_namespaces_count) create string_equality_tester namespaces.set_key_equality_tester (string_equality_tester) end feature -- Status uses_namespace (ns: STRING): BOOLEAN is -- Does message use this namespace? require Namespace_valid: ns /= Void do Result := ns.is_equal (namespace_user) or ns.is_equal (namespace_jxta) if not Result then Result := special_namespaces.has (ns) end end feature -- Access element_by_name (name: STRING): P2P_MESSAGE_ELEMENT is -- First message element with given name require Name_existent: name /= Void do from namespaces.start until Result /= Void or namespaces.after loop Result := element_by_namespace_and_name (namespaces.key_for_iteration, name) namespaces.forth end ensure Result_applies_filter: (Result /= Void) implies (name.is_equal (Result.name)) end element_by_namespace_and_name (namespace, name: STRING): P2P_MESSAGE_ELEMENT is -- First message element with given namespace and name require Name_existent: name /= Void Namespace_existent: namespace /= Void local list: DS_LINKED_LIST [P2P_MESSAGE_ELEMENT] do if namespaces.has (namespace) then list := namespaces.item (namespace) from list.start until Result /= Void or list.after loop if equal (name, list.item_for_iteration.name) then Result := list.item_for_iteration end list.forth end end ensure Result_applies_filter: (Result /= Void) implies (name.is_equal (Result.name) and namespace.is_equal (Result.namespace)) end jxta_element_by_name (name: STRING): P2P_MESSAGE_ELEMENT is -- First message element in JXTA namespace with given name require Name_existent: name /= Void do Result := element_by_namespace_and_name (namespace_jxta, name) ensure Result_applies_filter: (Result /= Void) implies (name.is_equal (Result.name) and namespace_jxta.is_equal (Result.namespace)) end all_elements: DS_LIST [P2P_MESSAGE_ELEMENT] is -- All message elements do create {DS_LINKED_LIST [P2P_MESSAGE_ELEMENT]} Result.make from namespaces.start until namespaces.after loop Result.extend_last (namespaces.item_for_iteration) namespaces.forth end ensure Result_existent: Result /= Void end all_elements_of_namespace (namespace: STRING): DS_LIST [P2P_MESSAGE_ELEMENT] is -- All message elements of given namespace require Namespace_valid: namespace /= Void do if namespaces.has (namespace) then Result := namespaces.item (namespace).twin else create {DS_LINKED_LIST [P2P_MESSAGE_ELEMENT]} Result.make end ensure Result_existent: Result /= Void end special_namespaces: DS_LIST [STRING] is -- All used special namespaces incl. signature namespaces local string_equality_tester: KL_EQUALITY_TESTER [STRING] element_cursor: DS_LIST_CURSOR [P2P_MESSAGE_ELEMENT] do create {DS_LINKED_LIST [STRING]} Result.make create string_equality_tester Result.set_equality_tester (string_equality_tester) from namespaces.start until namespaces.after loop if not namespaces.key_for_iteration.is_equal (namespace_user) and not namespaces.key_for_iteration.is_equal (namespace_jxta) then Result.put_last (namespaces.key_for_iteration) end namespaces.forth end -- now look for signatures which use their own namespace from element_cursor := all_elements.new_cursor element_cursor.start until element_cursor.after loop extend_signature_namespace (element_cursor.item, Result) element_cursor.forth end ensure Result_set: Result /= Void Namespaces_cleaned_up: (all_elements.count = 0) implies (Result.count = 0) end Namespace_jxta: STRING is "jxta" -- Reserved namespace for JXTA protocol intern message elements Namespace_user: STRING is "" -- Reserved namespace for user applications and services feature -- Element change extend (an_element: P2P_MESSAGE_ELEMENT) is -- Add element to end if not existent yet require Element_valid: an_element /= Void local namespace: DS_LINKED_LIST [P2P_MESSAGE_ELEMENT] do if namespaces.has (an_element.namespace) then namespace := namespaces.item (an_element.namespace) if not namespace.has (an_element) then namespace.put_last (an_element) end else create namespace.make namespace.put_last (an_element) namespaces.force (namespace, an_element.namespace) end ensure Element_existent: all_elements.has (an_element) end replace (an_element: P2P_MESSAGE_ELEMENT) is -- Remove all elements with given namespace and name and inserts new element require Element_valid: an_element /= Void local namespace: DS_LINKED_LIST [P2P_MESSAGE_ELEMENT] do if namespaces.has (an_element.namespace) then namespace := namespaces.item (an_element.namespace) from namespace.start until namespace.after loop if equal (an_element.name, namespace.item_for_iteration.name) then namespace.remove_at else namespace.forth end end namespace.put_last (an_element) else create namespace.make namespace.put_last (an_element) namespaces.force (namespace, an_element.namespace) end ensure Element_existent: all_elements.has (an_element) end feature -- Removal remove (an_element: P2P_MESSAGE_ELEMENT) is -- Remove element require Element_valid: an_element /= Void local namespace: DS_LINKED_LIST [P2P_MESSAGE_ELEMENT] do if namespaces.has (an_element.namespace) then namespace := namespaces.item (an_element.namespace) namespace.delete (an_element) -- remove namespace if no element remaining if namespace.count = 0 then namespaces.remove (an_element.namespace) end end ensure Element_removed: not all_elements.has (an_element) end clear_all is -- Remove all elements do from namespaces.start until namespaces.after loop namespaces.remove (namespaces.key_for_iteration) end ensure Elements_empty: all_elements.count = 0 Namespaces_empty: special_namespaces.count = 0 end feature -- Output out: STRING is -- Nice string representation local list: DS_LIST_CURSOR [P2P_MESSAGE_ELEMENT] do create Result.make_empty from namespaces.start until namespaces.after loop from list := namespaces.item_for_iteration.new_cursor list.start until list.after loop Result.append ("%T" + list.item.out + "%N") list.forth end namespaces.forth end end feature {NONE} -- Implementation namespaces: DS_HASH_TABLE [DS_LINKED_LIST [P2P_MESSAGE_ELEMENT], STRING] Initial_namespaces_count: INTEGER is 2 extend_signature_namespace (e: P2P_MESSAGE_ELEMENT; allns: DS_LIST [STRING]) is -- Adds element signature namespace to a list if it doesn't exist in namespaces require Params_existent: e /= Void and allns /= Void do if e.signature /= Void then if not e.signature.namespace.is_equal (namespace_jxta) and not e.signature.namespace.is_equal (namespace_user) and not namespaces.has (e.signature.namespace) and not allns.has (e.signature.namespace) then allns.put_last (e.signature.namespace) end extend_signature_namespace (e.signature, allns) end end end