note
	description: "Decoding of arbitrary objects graphs between sessions of programs containing the same types. It basically takes care of potential reordering of attributes from one system to the other."
	legal: "See notice at end of class."
	status: "See notice at end of class."
	date: "$Date: 2020-05-19 14:29:33 +0000 (Tue, 19 May 2020) $"
	revision: "$Revision: 104259 $"

class 
	SED_INDEPENDENT_DESERIALIZER

obsolete "Use SED_RECOVERABLE_DESERIALIZER instead."

inherit
	SED_BASIC_DESERIALIZER
		redefine
			read_header,
			new_attribute_offset,
			read_persistent_field_count,
			clear_internal_data,
			is_transient_retrieval_required,
			is_store_settings_enabled
		end

create 
	make

feature {NONE} -- Implementation: access

	attributes_mapping: detachable SPECIAL [detachable SPECIAL [INTEGER_32]]
			-- Mapping for each dynamic type id between old attribute location
			-- and new attribute location.

	new_attribute_offset (a_new_type_id, a_old_offset: INTEGER_32): INTEGER_32
			-- Given attribute offset a_old_offset in the stored object whose dynamic type id
			-- is now a_new_type_id, retrieve new offset in a_new_type_id.
		do
			if attached attributes_mapping as l_map and then l_map.valid_index (a_new_type_id) and then attached l_map.item (a_new_type_id) as l_entry and then l_entry.valid_index (a_old_offset) then
				Result := l_entry.item (a_old_offset)
			end
		end
	
feature {NONE} -- Status report

	is_transient_retrieval_required: BOOLEAN
			-- Do we need to retrieve transient attribute with their default value?
			-- This is necessary for Session/Basic storing where we expect the same
			-- object layout.
		do
			Result := False
		end

	is_store_settings_enabled: BOOLEAN
			-- Are settings stored?
			-- By default not for SED_INDEPENDENT_DESERIALIZER.
		do
			Result := False
		end
	
feature {NONE} -- Implementation

	read_header (a_count: NATURAL_32)
			-- Read header which contains mapping between dynamic type and their
			-- string representation.
		local
			i, j, nb: INTEGER_32
			l_deser: like deserializer
			l_reflector: like reflector
			l_table: like dynamic_type_table
			l_old_dtype, l_new_dtype: INTEGER_32
			l_type_str: STRING_8
		do
			l_reflector := reflector
			l_deser := deserializer
			read_settings
			nb := l_deser.read_compressed_natural_32.to_integer_32
			create l_table.make_filled (0, nb)
			create attributes_mapping.make_filled (Void, nb)
			from
				j := 0
			until
				j = 2
			loop
				from
					i := 0
				until
					i = nb
				loop
					l_old_dtype := l_deser.read_compressed_natural_32.to_integer_32
					l_type_str := l_deser.read_string_8
					l_new_dtype := l_reflector.dynamic_type_from_string (l_type_str)
					if l_new_dtype >= 0 then
						if not l_table.valid_index (l_old_dtype) then
							l_table := l_table.aliased_resized_area_with_default (0, (l_old_dtype + 1).max (l_table.count * 2))
						end;
						l_table.put (l_new_dtype, l_old_dtype)
					else
						add_error (Error_factory.new_missing_type_error (l_type_str, l_type_str))
					end
					i := i + 1
				end
				if j = 0 then
					nb := l_deser.read_compressed_natural_32.to_integer_32
				end
				j := j + 1
			end
			dynamic_type_table := l_table
			from
				i := 0
				nb := l_deser.read_compressed_natural_32.to_integer_32
			until
				i = nb
			loop
				l_old_dtype := l_deser.read_compressed_natural_32.to_integer_32
				if l_table.valid_index (l_old_dtype) then
					read_attributes (l_table.item (l_old_dtype))
				else
					raise_fatal_error (Error_factory.new_internal_error ("Cannot read attributes data"))
				end
				i := i + 1
			end
			read_object_table (a_count)
		end

	read_persistent_field_count (a_reflected_object: REFLECTED_OBJECT): INTEGER_32
			-- Number of fields we are going to read from a_reflected_object in the the retrieved system.
		local
			l_dtype: INTEGER_32
		do
			l_dtype := a_reflected_object.dynamic_type
			if attached attributes_mapping as l_map and then l_map.valid_index (l_dtype) and then attached l_map.item (l_dtype) as l_entry then
				Result := l_entry.count - 1
			else
				raise_fatal_error (Error_factory.new_internal_error ("Cannot retrieve stored count"))
			end
		end

	read_attributes (a_dtype: INTEGER_32)
			-- Read attribute description for a_dtype where a_dtype is a dynamic type
			-- from the current system.
		require
			a_dtype_non_negative: a_dtype >= 0
			attributes_mapping_not_void: attributes_mapping /= Void
		local
			l_deser: like deserializer
			l_map: like attributes_map
			l_mapping: SPECIAL [INTEGER_32]
			l_name: STRING_8
			l_old_dtype, l_dtype: INTEGER_32
			i, nb: INTEGER_32
			a: like attributes_mapping
			l_attribute_type: INTEGER_32
		do
			l_deser := deserializer
			nb := l_deser.read_compressed_natural_32.to_integer_32
			if nb = reflector.persistent_field_count_of_type (a_dtype) then
				from
					i := 1
					l_map := attributes_map (a_dtype)
					nb := nb + 1
					create l_mapping.make_empty (nb);
					l_mapping.extend (0)
				until
					i = nb
				loop
					l_old_dtype := l_deser.read_compressed_natural_32.to_integer_32
					l_dtype := new_dynamic_type_id (l_old_dtype)
					l_name := l_deser.read_string_8
					if l_dtype >= 0 then
						if attached l_map.item (l_name) as l_item then
							l_attribute_type := l_item.dtype
							if l_attribute_type = l_dtype then
								l_mapping.extend (l_item.position)
							else
								add_error (Error_factory.new_attribute_mismatch (a_dtype, l_name, l_attribute_type, l_dtype))
							end
						else
							add_error (Error_factory.new_missing_attribute_error (a_dtype, l_name))
						end
					else
						add_error (Error_factory.new_unknown_attribute_type_error (a_dtype, l_name))
					end
					i := i + 1
				end
				if not has_error then
					a := attributes_mapping
					if a /= Void then
						if not a.valid_index (a_dtype) then
							a := a.aliased_resized_area_with_default (Void, (a_dtype + 1).max (a.count * 2))
							attributes_mapping := a
						end;
						a.put (l_mapping, a_dtype)
					end
				end
			else
				add_error (Error_factory.new_attribute_count_mismatch (a_dtype, nb))
			end
		end

	attributes_map (a_dtype: INTEGER_32): HASH_TABLE [TUPLE [position: INTEGER_32; dtype: INTEGER_32], STRING_8]
			-- Attribute map for dynamic type a_dtype which records
			-- position and dynamic type for a given attribute name.
		require
			a_dtype_non_negative: a_dtype >= 0
		local
			l_reflector: like reflector
			i, nb: INTEGER_32
		do
			l_reflector := reflector
			from
				i := 1
				nb := l_reflector.field_count_of_type (a_dtype)
				create Result.make (nb)
				nb := nb + 1
			until
				i = nb
			loop
				Result.put ([i, l_reflector.field_static_type_of_type (i, a_dtype)], l_reflector.field_name_of_type (i, a_dtype))
				i := i + 1
			end
		ensure
			attributes_map_not_void: Result /= Void
		end
	
feature {NONE} -- Cleaning

	clear_internal_data
			-- Clear all allocated data
		do
			Precursor {SED_BASIC_DESERIALIZER}
			attributes_mapping := Void
		end
	
note
	library: "EiffelBase: Library of reusable components for Eiffel."
	copyright: "Copyright (c) 1984-2020, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
		Eiffel Software
		5949 Hollister Ave., Goleta, CA 93117 USA
		Telephone 805-685-1006, Fax 805-685-6869
		Website http://www.eiffel.com
		Customer support http://support.eiffel.com
	]"

end -- class SED_INDEPENDENT_DESERIALIZER

Generated by ISE EiffelStudio