From dd6b74326ee32aa16c0c6734ed031083f2d1bfea Mon Sep 17 00:00:00 2001 From: Jocelyn Fiat Date: Tue, 14 Feb 2012 12:57:01 +0100 Subject: [PATCH] Added notion of synchronization between error handler this is convenient to integrate two components using their own ERROR_HANDLER (not sharing the same object) --- library/error/src/error_handler.e | 151 +++++++++++++++++++++++++++-- library/error/tests/test_error.e | 124 +++++++++++++++++++++++ library/error/tests/tests-safe.ecf | 18 ++++ 3 files changed, 287 insertions(+), 6 deletions(-) create mode 100644 library/error/tests/test_error.e create mode 100644 library/error/tests/tests-safe.ecf diff --git a/library/error/src/error_handler.e b/library/error/src/error_handler.e index c6e72c8b..347585f8 100644 --- a/library/error/src/error_handler.e +++ b/library/error/src/error_handler.e @@ -21,7 +21,7 @@ feature {NONE} -- Initialization make -- Initialize `Current'. do - create {ARRAYED_LIST [ERROR]} errors.make (3) + create {ARRAYED_LIST [like errors.item]} errors.make (3) create error_added_actions end @@ -60,12 +60,139 @@ feature -- Events error_added_actions: ACTION_SEQUENCE [TUPLE [ERROR]] -- Actions triggered when a new error is added +feature -- Synchronization + + add_synchronized_handler (h: ERROR_HANDLER) + --| the same handler can be added more than once + --| it will be synchronized only once + require + no_cycle: not has_synchronized_handler_in_cycle (h) + local + lst: like synchronized_handlers + do + lst := synchronized_handlers + if lst = Void then + create {ARRAYED_LIST [like synchronized_handlers.item]} lst.make (0) + lst.compare_references + synchronized_handlers := lst + end + if lst.has (h) then + check attached h.synchronized_handlers as h_lst and then h_lst.has (Current) end + else + lst.extend (h) + h.add_synchronized_handler (Current) + end + end + + has_synchronized_handler_in_cycle (h: ERROR_HANDLER): BOOLEAN + do + Result := False + end + +feature {ERROR_HANDLER} -- Synchronization implementation + + synchronized_handlers: detachable LIST [ERROR_HANDLER] + -- Synchronized handlers + + synchronize_error_from (e: ERROR; h_lst: LIST [ERROR_HANDLER]) + -- Called by error_handler during synchronization process + -- if `synchronized_handlers' is Void, this means Current is synchronizing + -- this is to prevent infinite cycle iteration + require + not h_lst.has (Current) + do + h_lst.extend (Current) + + if attached synchronized_handlers as lst then + synchronized_handlers := Void + add_error (e) + across + lst as c + loop + if not h_lst.has (c.item) then + c.item.synchronize_error_from (e, h_lst) + end + end + synchronized_handlers := lst + else + -- In synchronization + end + end + + synchronize_reset_from (h_lst: LIST [ERROR_HANDLER]) + -- Called by error_handler during synchronization process + -- if `synchronized_handlers' is Void, this means Current is synchronizing + -- this is to prevent infinite cycle iteration + require + not h_lst.has (Current) + do + h_lst.extend (Current) + if attached synchronized_handlers as lst then + synchronized_handlers := Void + reset + across + lst as c + loop + if not h_lst.has (c.item) then + c.item.synchronize_reset_from (h_lst) + end + end + synchronized_handlers := lst + else + -- In synchronization + end + end + + remove_synchronized_handler (h: ERROR_HANDLER) + do + if attached synchronized_handlers as lst then + lst.prune_all (h) + if lst.is_empty then + synchronized_handlers := Void + end + end + end + feature {NONE} -- Event: implementation on_error_added (e: ERROR) -- Error `e' was just added + local + sync_list: LINKED_LIST [ERROR_HANDLER] do error_added_actions.call ([e]) + if attached synchronized_handlers as lst then + synchronized_handlers := Void + create sync_list.make + sync_list.extend (Current) + across + lst as c + loop + if not sync_list.has (c.item) then + c.item.synchronize_error_from (e, sync_list) + end + end + synchronized_handlers := lst + end + end + + on_reset + local + sync_list: LINKED_LIST [ERROR_HANDLER] + do + if attached synchronized_handlers as lst then + synchronized_handlers := Void + create sync_list.make + sync_list.extend (Current) + across + lst as c + loop + if not sync_list.has (c.item) then + c.item.synchronize_reset_from (sync_list) + end + end + synchronized_handlers := lst + end end feature -- Basic operation @@ -138,18 +265,30 @@ feature -- Element changes -- Concatenate into a single error if any do if count > 1 and then attached as_single_error as e then - wipe_out - errors.force (e) + reset + add_error (e) end end - reset, wipe_out + reset do - errors.wipe_out + if errors.count > 0 then + errors.wipe_out + on_reset + end + end + + destroy + do + error_added_actions.wipe_out + if attached synchronized_handlers as lst then + lst.item.remove_synchronized_handler (Current) + end + synchronized_handlers := Void end note - copyright: "Copyright (c) 1984-2011, Eiffel Software and others" + copyright: "2011-2012, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software diff --git a/library/error/tests/test_error.e b/library/error/tests/test_error.e new file mode 100644 index 00000000..f0e1badf --- /dev/null +++ b/library/error/tests/test_error.e @@ -0,0 +1,124 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date$" + revision: "$Revision$" + testing: "type/manual" + +class + TEST_ERROR + +inherit + EQA_TEST_SET + +feature -- Test routines + + test_error + note + testing: "error" + local + h: ERROR_HANDLER + cl: CELL [INTEGER] + do + create h.make + h.add_custom_error (123, "abc", "abc error occurred") + h.add_custom_error (456, "abc", "abc error occurred") + assert ("has 2 errors", h.count = 2) + h.reset + assert ("reset then no error", h.count = 0) + + -- error_added_actions + create cl.put (0) + h.error_added_actions.extend (agent (i_e: ERROR; i_cl: CELL [INTEGER]) do i_cl.replace (i_cl.item + 1) end(?, cl)) + h.add_custom_error (123, "abc", "abc error occurred") + h.add_custom_error (456, "abc", "abc error occurred") + assert ("has 2 errors, same as counted", h.count = 2 and h.count = cl.item) + + end + + test_sync_2 + note + testing: "error" + local + h1, h2: ERROR_HANDLER +-- cl: CELL [INTEGER] + do + create h1.make + create h2.make + h1.add_synchronized_handler (h2) + + h1.add_custom_error (123, "abc", "abc error occurred") + h1.add_custom_error (456, "abc", "abc error occurred") + + assert ("has 2 errors", h1.count = 2 and h2.count = h1.count) + + h1.reset + assert ("reset then no error", h1.count = 0 and h2.count = h1.count) + + end + + test_sync_3 + note + testing: "error" + local + h1, h2, h3: ERROR_HANDLER +-- cl: CELL [INTEGER] + do + create h1.make + create h2.make + create h3.make + + h1.add_synchronized_handler (h2) + h2.add_synchronized_handler (h3) + + h1.add_custom_error (123, "abc", "abc error occurred") + h1.add_custom_error (456, "abc", "abc error occurred") + + assert ("has 2 errors", h1.count = 2 and h2.count = h1.count and h3.count = h2.count) + + h1.reset + assert ("reset then no error", h1.count = 0 and h2.count = h1.count and h3.count = h2.count) + + end + + test_sync_3_with_cycle + note + testing: "error" + local + h1, h2, h3: ERROR_HANDLER +-- cl: CELL [INTEGER] + do + create h1.make + create h2.make + create h3.make + + h1.add_synchronized_handler (h2) + h2.add_synchronized_handler (h3) + h3.add_synchronized_handler (h1) + + h1.add_custom_error (123, "abc", "abc error occurred") + h1.add_custom_error (456, "abc", "abc error occurred") + + assert ("has 2 errors", h1.count = 2 and h2.count = h1.count and h3.count = h2.count) + + h1.reset + assert ("reset then no error", h1.count = 0 and h2.count = h1.count and h3.count = h2.count) + + end + + +note + copyright: "Copyright (c) 1984-2011, 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 + + diff --git a/library/error/tests/tests-safe.ecf b/library/error/tests/tests-safe.ecf new file mode 100644 index 00000000..46989ec4 --- /dev/null +++ b/library/error/tests/tests-safe.ecf @@ -0,0 +1,18 @@ + + + + + + /.git$ + /EIFGENs$ + /.svn$ + + + + + + + +