diff --git a/cms/cms-safe.ecf b/cms/cms-safe.ecf index 235bd74..5da317c 100644 --- a/cms/cms-safe.ecf +++ b/cms/cms-safe.ecf @@ -10,6 +10,7 @@ + diff --git a/cms/src/configuration/cms_default_setup.e b/cms/src/configuration/cms_default_setup.e index 8918a36..eabc20c 100644 --- a/cms/src/configuration/cms_default_setup.e +++ b/cms/src/configuration/cms_default_setup.e @@ -17,6 +17,7 @@ feature {NONE} -- Initialization make (a_layout: CMS_LAYOUT) do + create error_handler.make layout := a_layout create configuration.make (layout) initialize @@ -28,7 +29,6 @@ feature {NONE} -- Initialization create modules.make (3) build_api_service build_mailer - initialize_modules end @@ -61,7 +61,6 @@ feature {NONE} -- Initialization -- m.enable -- modules.extend (m) - create {NODE_MODULE} m.make (Current) m.enable modules.extend (m) @@ -89,15 +88,44 @@ feature -- Access build_api_service local l_database: DATABASE_CONNECTION + l_retry: BOOLEAN + l_message: STRING do - to_implement ("Refactor database setup") - if attached (create {JSON_CONFIGURATION}).new_database_configuration (layout.application_config_path) as l_database_config then - create {DATABASE_CONNECTION_MYSQL} l_database.login_with_connection_string (l_database_config.connection_string) - create api_service.make (create {CMS_STORAGE_MYSQL}.make (l_database)) + if not l_retry then + to_implement ("Refactor database setup") + if attached (create {JSON_CONFIGURATION}).new_database_configuration (layout.application_config_path) as l_database_config then + create {DATABASE_CONNECTION_MYSQL} l_database.login_with_connection_string (l_database_config.connection_string) + create api_service.make (create {CMS_STORAGE_MYSQL}.make (l_database)) + else + create {DATABASE_CONNECTION_NULL} l_database.make_common + create api_service.make (create {CMS_STORAGE_NULL}) + end else + to_implement ("Workaround code, persistence layer does not implement yet this kind of error handling.") + -- error hanling. create {DATABASE_CONNECTION_NULL} l_database.make_common create api_service.make (create {CMS_STORAGE_NULL}) + create l_message.make (1024) + if attached ((create {EXCEPTION_MANAGER}).last_exception) as l_exception then + if attached l_exception.description as l_description then + l_message.append (l_description.as_string_32) + l_message.append ("%N%N") + elseif attached l_exception.trace as l_trace then + l_message.append (l_trace) + l_message.append ("%N%N") + else + l_message.append (l_exception.out) + l_message.append ("%N%N") + end + else + l_message.append ("The application crash without available information") + l_message.append ("%N%N") + end + error_handler.add_custom_error (0, " Database Connection ", l_message) end + rescue + l_retry := True + retry end build_auth_engine diff --git a/cms/src/configuration/cms_setup.e b/cms/src/configuration/cms_setup.e index f0af327..0e6189d 100644 --- a/cms/src/configuration/cms_setup.e +++ b/cms/src/configuration/cms_setup.e @@ -32,6 +32,12 @@ feature -- Access deferred end + +feature -- Status Report + + error_handler: ERROR_HANDLER + -- Error handler. + feature -- Access: Site site_id: READABLE_STRING_8 diff --git a/cms/src/service/cms_service.e b/cms/src/service/cms_service.e index 37a4759..84b67e6 100644 --- a/cms/src/service/cms_service.e +++ b/cms/src/service/cms_service.e @@ -165,9 +165,15 @@ feature -- Filters do log.write_debug (generator + ".create_filter") l_filter := Void + -- Maintenance create {WSF_MAINTENANCE_FILTER} f f.set_next (l_filter) + l_filter := f + + -- Error Filter + create {CMS_ERROR_FILTER} f.make (setup) + f.set_next (l_filter) l_filter := f -- Include filters from modules diff --git a/cms/src/service/filter/cms_error_filter.e b/cms/src/service/filter/cms_error_filter.e new file mode 100644 index 0000000..8a2f154 --- /dev/null +++ b/cms/src/service/filter/cms_error_filter.e @@ -0,0 +1,33 @@ +note + description: "Summary description for {CMS_ERROR_FILTER}." + date: "$Date$" + revision: "$Revision$" + +class + CMS_ERROR_FILTER + +inherit + + WSF_URI_TEMPLATE_HANDLER + CMS_HANDLER + WSF_FILTER + +create + make + +feature -- Basic operations + + execute (req: WSF_REQUEST; res: WSF_RESPONSE) + -- Execute the filter + do + if not setup.error_handler.has_error then + log.write_information (generator + ".execute") + execute_next (req, res) + else + log.write_critical (generator + ".execute" + setup.error_handler.as_string_representation ) + (create {ERROR_500_CMS_RESPONSE}.make (req, res, setup, "master2/error")).execute + setup.error_handler.reset + end + end + +end diff --git a/persistence/implementation/common/database/database_connection.e b/persistence/implementation/common/database/database_connection.e index 7591273..cfb9fd9 100644 --- a/persistence/implementation/common/database/database_connection.e +++ b/persistence/implementation/common/database/database_connection.e @@ -10,7 +10,7 @@ inherit DATABASE_CONFIG - SHARED_ERROR + SHARED_ERROR_HANDLER feature {NONE} -- Initialization @@ -72,6 +72,65 @@ feature -- Database Setup keep_connection: BOOLEAN -- Keep connection alive? +feature -- Transactions + + begin_transaction + -- Start a transaction which will be terminated by a call to `rollback' or `commit'. + local + rescued: BOOLEAN + do + if not rescued then + if db_control.is_ok then + db_control.begin + else + database_error_handler.add_database_error (db_control.error_message_32, db_control.error_code) + end + end + rescue + rescued := True + exception_as_error ((create {EXCEPTION_MANAGER}).last_exception) + db_control.reset + retry + end + + commit + -- Commit updates in the database. + local + rescued: BOOLEAN + do + if not rescued then + if db_control.is_ok then + db_control.commit + else + database_error_handler.add_database_error (db_control.error_message_32, db_control.error_code) + end + end + rescue + rescued := True + exception_as_error ((create {EXCEPTION_MANAGER}).last_exception) + db_control.reset + retry + end + + rollback + -- Rollback updates in the database. + local + rescued: BOOLEAN + do + if not rescued then + if db_control.is_ok then + db_control.rollback + else + database_error_handler.add_database_error (db_control.error_message_32, db_control.error_code) + end + end + rescue + rescued := True + exception_as_error ((create {EXCEPTION_MANAGER}).last_exception) + db_control.reset + retry + end + feature -- Change Element not_keep_connection diff --git a/persistence/implementation/common/database/database_handler.e b/persistence/implementation/common/database/database_handler.e index 3551e4a..875b7a7 100644 --- a/persistence/implementation/common/database/database_handler.e +++ b/persistence/implementation/common/database/database_handler.e @@ -8,7 +8,7 @@ deferred class inherit - SHARED_ERROR + SHARED_ERROR_HANDLER feature -- Access @@ -42,15 +42,15 @@ feature -- Modifiers feature -- Functionality Store Procedures - execute_reader - -- Execute store. + execute_store_reader + -- Execute a `store' to read data. require store_not_void: store /= void deferred end - execute_writer - -- Execute store. + execute_store_writer + -- Execute a `store' to write data. require store_not_void: store /= void deferred @@ -59,14 +59,14 @@ feature -- Functionality Store Procedures feature -- SQL Queries execute_query - -- Execute query. + -- Execute sql query, the read data from the database. require query_not_void: query /= void deferred end execute_change - -- Execute sqlquery that update/add data. + -- Execute sql query that update/add data. require query_not_void: query /= void deferred @@ -147,14 +147,49 @@ feature -- Access feature -- Status Report - has_error: BOOLEAN - -- Is there an error? - count: INTEGER -- Number of rows, last execution. deferred end + connection: DATABASE_CONNECTION + -- Database connection. + + db_control: DB_CONTROL + -- Database control. + do + Result := connection.db_control + end + + db_result: detachable DB_RESULT + -- Database query result. + + db_selection: detachable DB_SELECTION + -- Database selection. + + db_change: detachable DB_CHANGE + -- Database modification. + +feature -- Error handling + + check_database_change_error + -- Check database error from `db_change'. + do + if attached db_change as l_change and then not l_change.is_ok then + database_error_handler.add_database_error (l_change.error_message_32, l_change.error_code) + log.write_error (generator + ".check_database_change_error: " + l_change.error_message_32) + end + end + + check_database_selection_error + -- Check database error from `db_selection'. + do + if attached db_selection as l_selection and then not l_selection.is_ok then + database_error_handler.add_database_error (l_selection.error_message_32, l_selection.error_code) + log.write_error (generator + ".check_database_selection_error: " + l_selection.error_message_32) + end + end + feature {NODE_DATA_PROVIDER}-- Implementation connect diff --git a/persistence/implementation/common/database/database_handler_impl.e b/persistence/implementation/common/database/database_handler_impl.e index 96078ee..55bde06 100644 --- a/persistence/implementation/common/database/database_handler_impl.e +++ b/persistence/implementation/common/database/database_handler_impl.e @@ -21,7 +21,6 @@ feature {NONE} -- Initialization do connection := a_connection create last_query.make_now - set_successful ensure connection_not_void: connection /= Void last_query_not_void: last_query /= Void @@ -29,71 +28,52 @@ feature {NONE} -- Initialization feature -- Functionality - execute_reader + execute_store_reader -- Execute stored procedure that returns data. local l_db_selection: DB_SELECTION l_retried: BOOLEAN do if not l_retried then - if not keep_connection then - connect - end - if attached store as l_store then create l_db_selection.make db_selection := l_db_selection items := l_store.execute_reader (l_db_selection) + check_database_selection_error end - - if not keep_connection then - disconnect - end - set_successful log.write_debug ( generator+".execute_reader Successful") end rescue - set_last_error_from_exception ("Store procedure execution") - log.write_critical (generator+ ".execute_reader " + last_error_message) - if is_connected then - disconnect - end l_retried := True + exception_as_error ((create {EXCEPTION_MANAGER}).last_exception) + if attached db_selection as l_selection then + l_selection.reset + end retry end - execute_writer + execute_store_writer -- Execute stored procedure that update/add data. local l_db_change: DB_CHANGE l_retried : BOOLEAN do if not l_retried then - if not keep_connection and not is_connected then - connect - end if attached store as l_store then create l_db_change.make - db_update := l_db_change + db_change := l_db_change l_store.execute_writer (l_db_change) - if not l_store.has_error then - db_control.commit - end + check_database_change_error end - if not keep_connection then - disconnect - end - set_successful log.write_debug ( generator+".execute_writer Successful") end rescue - set_last_error_from_exception ("Store procedure execution") - log.write_critical (generator+ ".execute_writer " + last_error_message) - if is_connected then - disconnect - end l_retried := True + exception_as_error ((create {EXCEPTION_MANAGER}).last_exception) + if attached db_change as l_change then + l_change.reset + end retry end @@ -106,60 +86,43 @@ feature -- SQL Queries l_retried: BOOLEAN do if not l_retried then - if not keep_connection then - connect - end - if attached query as l_query then create l_db_selection.make db_selection := l_db_selection items := l_query.execute_reader (l_db_selection) + check_database_selection_error end - if not keep_connection then - disconnect - end - set_successful end rescue - set_last_error_from_exception ("execute_query") - log.write_critical (generator+ ".execute_query " + last_error_message) - if is_connected then - disconnect - end l_retried := True + exception_as_error ((create {EXCEPTION_MANAGER}).last_exception) + if attached db_selection as l_selection then + l_selection.reset + end retry end execute_change - -- Execute sqlquery that update/add data. + -- Execute sql_query that update/add data. local l_db_change: DB_CHANGE l_retried : BOOLEAN do if not l_retried then - if not keep_connection and not is_connected then - connect - end - if attached query as l_query then create l_db_change.make - db_update := l_db_change + db_change := l_db_change l_query.execute_change (l_db_change) - db_control.commit + check_database_change_error end - if not keep_connection then - disconnect - end - set_successful end rescue - set_last_error_from_exception ("Store procedure execution") - log.write_critical (generator+ ".execute_writer " + last_error_message) - if is_connected then - disconnect - end l_retried := True + exception_as_error ((create {EXCEPTION_MANAGER}).last_exception) + if attached db_change as l_change then + l_change.reset + end retry end @@ -207,24 +170,6 @@ feature -- Iteration feature {NONE} -- Implementation - connection: DATABASE_CONNECTION - -- Database connection. - - db_control: DB_CONTROL - -- Database control. - do - Result := connection.db_control - end - - db_result: detachable DB_RESULT - -- Database query result. - - db_selection: detachable DB_SELECTION - -- Database selection. - - db_update: detachable DB_CHANGE - -- Database modification. - last_query: DATE_TIME -- Last time when a query was executed. @@ -263,7 +208,7 @@ feature {NONE} -- Implementation affected_row_count: INTEGER -- The number of rows changed, deleted, or inserted by the last statement. do - if attached db_update as l_update then + if attached db_change as l_update then Result := l_update.affected_row_count end end diff --git a/persistence/implementation/common/database/database_iteration_cursor.e b/persistence/implementation/common/database/database_iteration_cursor.e index f38d844..1688b76 100644 --- a/persistence/implementation/common/database/database_iteration_cursor.e +++ b/persistence/implementation/common/database/database_iteration_cursor.e @@ -1,5 +1,5 @@ note - description: "External iteration cursor for {ESA_DATABASE_HANDLER}" + description: "External iteration cursor for {DATABASE_HANDLER}" date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $" revision: "$Revision: 95678 $" diff --git a/persistence/implementation/common/database/database_no_change_error.e b/persistence/implementation/common/database/database_no_change_error.e new file mode 100644 index 0000000..6855279 --- /dev/null +++ b/persistence/implementation/common/database/database_no_change_error.e @@ -0,0 +1,27 @@ +note + description: "Summary description for {DATABASE_NO_CHANGE_ERROR}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + DATABASE_NO_CHANGE_ERROR + +inherit + DATABASE_ERROR + redefine + make_from_message + end + +create + make_from_message + +feature {NONE} -- Init + + make_from_message (a_m: like message; a_code: like code) + -- Create from `a_m' + do + make (a_code, once "Database No Change Error", a_m) + end + +end diff --git a/persistence/implementation/common/database/database_query.e b/persistence/implementation/common/database/database_query.e index 1a5f8cd..4acec0c 100644 --- a/persistence/implementation/common/database/database_query.e +++ b/persistence/implementation/common/database/database_query.e @@ -8,14 +8,14 @@ class inherit - SHARED_ERROR + SHARED_ERROR_HANDLER REFACTORING_HELPER create data_reader -feature -- Intialization +feature {NONE} -- Intialization data_reader (a_query: STRING; a_parameters: STRING_TABLE [detachable ANY]) -- SQL data reader for the query `a_query' with arguments `a_parameters' @@ -29,6 +29,8 @@ feature -- Intialization parameters_set: parameters = a_parameters end +feature -- Execution + execute_reader (a_base_selection: DB_SELECTION): detachable LIST [DB_RESULT] -- Execute the Current sql query. do @@ -42,7 +44,6 @@ feature -- Intialization a_base_selection.load_result Result := a_base_selection.container else - set_last_error (a_base_selection.error_message_32, generator + ".execute_reader" ) log.write_error (generator + "." + a_base_selection.error_message_32) end unset_map_name (a_base_selection) @@ -50,17 +51,12 @@ feature -- Intialization end execute_change (a_base_change: DB_CHANGE) - -- Execute the Current sql query . + -- Execute the Current sql query to change/update data in the database. do to_implement ("Check test dynamic sequel. to redesign.") set_map_name (a_base_change) a_base_change.set_query (query) a_base_change.execute_query - if a_base_change.is_ok then - else - set_last_error (a_base_change.error_message_32, generator + ".execute_reader" ) - log.write_error (generator + "." + a_base_change.error_message_32) - end unset_map_name (a_base_change) end @@ -72,17 +68,6 @@ feature -- Access parameters: STRING_TABLE [detachable ANY] -- query parameters. -feature -- Status Report - - has_error: BOOLEAN - -- is there an error? - - error_message: detachable STRING_32 - -- Error message if any. - - error_code: INTEGER - -- Error code. - feature {NONE} -- Implementation set_map_name (a_base_selection: DB_EXPRESSION) @@ -140,4 +125,4 @@ feature {NONE} -- Implementation end -end -- ESA_DATABASE_QUERY +end -- DATABASE_QUERY diff --git a/persistence/implementation/common/database/error/database_error.e b/persistence/implementation/common/database/error/database_error.e new file mode 100644 index 0000000..2dcd646 --- /dev/null +++ b/persistence/implementation/common/database/error/database_error.e @@ -0,0 +1,23 @@ +note + description: "Error from database" + date: "$Date: 2013-08-08 16:39:49 -0300 (ju. 08 de ago. de 2013) $" + revision: "$Revision: 195 $" + +class + DATABASE_ERROR + +inherit + ERROR_CUSTOM + +create + make_from_message + +feature {NONE} -- Init + + make_from_message (a_m: like message; a_code: like code) + -- Create from `a_m' + do + make (a_code, once "Database Error", a_m) + end + +end diff --git a/persistence/implementation/common/database/database_error_handler.e b/persistence/implementation/common/database/error/database_error_handler.e similarity index 60% rename from persistence/implementation/common/database/database_error_handler.e rename to persistence/implementation/common/database/error/database_error_handler.e index a2718fe..5af3545 100644 --- a/persistence/implementation/common/database/database_error_handler.e +++ b/persistence/implementation/common/database/error/database_error_handler.e @@ -15,21 +15,21 @@ create feature -- Error operation add_database_error (a_message: READABLE_STRING_32; a_code: INTEGER) - -- Add a database error + -- Add a database error. local --- l_error: DATABASE_ERROR + l_error: DATABASE_ERROR do --- create l_error.make_from_message (a_message, a_code) --- add_error (l_error) + create l_error.make_from_message (a_message, a_code) + add_error (l_error) end add_database_no_change_error (a_message: READABLE_STRING_32; a_code: INTEGER) - -- Add a database error + -- Add a database error. local --- l_error: DATABASE_NO_CHANGE_ERROR + l_error: DATABASE_NO_CHANGE_ERROR do --- create l_error.make_from_message (a_message, a_code) --- add_error (l_error) + create l_error.make_from_message (a_message, a_code) + add_error (l_error) end end diff --git a/persistence/implementation/common/database/shared_error_handler.e b/persistence/implementation/common/database/error/shared_error_handler.e similarity index 78% rename from persistence/implementation/common/database/shared_error_handler.e rename to persistence/implementation/common/database/error/shared_error_handler.e index 9c26bfd..15c06c1 100644 --- a/persistence/implementation/common/database/shared_error_handler.e +++ b/persistence/implementation/common/database/error/shared_error_handler.e @@ -6,14 +6,26 @@ note class SHARED_ERROR_HANDLER +inherit + + SHARED_LOGGER + feature -- Access database_error_handler: DATABASE_ERROR_HANDLER - -- Error handler + -- Error handler. once create Result.make end +feature -- Status Report + + has_error: BOOLEAN + -- Has error? + do + Result := database_error_handler.has_error + end + feature -- Helper exception_as_error (a_e: like {EXCEPTION_MANAGER}.last_exception) diff --git a/persistence/implementation/mysql/src/cms_storage_mysql.e b/persistence/implementation/mysql/src/cms_storage_mysql.e index 74a72ce..47b74ca 100644 --- a/persistence/implementation/mysql/src/cms_storage_mysql.e +++ b/persistence/implementation/mysql/src/cms_storage_mysql.e @@ -21,6 +21,7 @@ feature {NONE} -- Initialization require is_connected: a_connection.is_connected do + connection := a_connection log.write_information (generator+".make_with_database is database connected? "+ a_connection.is_connected.out ) create node_provider.make (a_connection) create user_provider.make (a_connection) @@ -125,11 +126,14 @@ feature -- Change: user save_user (a_user: CMS_USER) -- Add a new user `a_user'. do + if attached a_user.password as l_password and then attached a_user.email as l_email then + connection.begin_transaction user_provider.new_user (a_user.name, l_password, l_email) + connection.commit else set_last_error ("User or Password not attached", generator + ".save_user") end @@ -282,4 +286,6 @@ feature {NONE} -- Post process user_provider: USER_DATA_PROVIDER -- User Data provider. + connection: DATABASE_CONNECTION + -- Current database connection. end diff --git a/persistence/implementation/mysql/src/database/database_connection_mysql.e b/persistence/implementation/mysql/src/database/database_connection_mysql.e index bc5f890..b9d173f 100644 --- a/persistence/implementation/mysql/src/database/database_connection_mysql.e +++ b/persistence/implementation/mysql/src/database/database_connection_mysql.e @@ -34,17 +34,11 @@ feature -- Initialization if keep_connection then connect end - set_successful else create db_control.make end rescue - create db_control.make - set_last_error_from_exception ("Connection execution") - log.write_critical (generator + ".make_common:" + last_error_message) - if is_connected then - disconnect - end + exception_as_error ((create {EXCEPTION_MANAGER}).last_exception) l_retried := True retry end @@ -66,17 +60,11 @@ feature -- Initialization if keep_connection then connect end - set_successful else create db_control.make end rescue - create db_control.make - set_last_error_from_exception ("Connection execution") - log.write_critical (generator + ".make_common:" + last_error_message) - if is_connected then - disconnect - end + exception_as_error ((create {EXCEPTION_MANAGER}).last_exception) l_retried := True retry end diff --git a/persistence/implementation/mysql/src/provider/node_data_provider.e b/persistence/implementation/mysql/src/provider/node_data_provider.e index 3bcfc84..59c9bae 100644 --- a/persistence/implementation/mysql/src/provider/node_data_provider.e +++ b/persistence/implementation/mysql/src/provider/node_data_provider.e @@ -34,7 +34,6 @@ feature -- Status Report is_successful: BOOLEAN -- Is the last execution sucessful? do - Result := db_handler.successful end feature -- Access @@ -481,13 +480,6 @@ feature {NONE} -- Implementation post_execution -- Post database execution. do - if db_handler.successful then - set_successful - else - if attached db_handler.last_error then - set_last_error_from_handler (db_handler.last_error) - end - end end end diff --git a/persistence/implementation/mysql/src/provider/role_data_provider.e b/persistence/implementation/mysql/src/provider/role_data_provider.e index 61590a0..8e82a64 100644 --- a/persistence/implementation/mysql/src/provider/role_data_provider.e +++ b/persistence/implementation/mysql/src/provider/role_data_provider.e @@ -35,7 +35,7 @@ feature -- Status Report is_successful: BOOLEAN -- Is the last execution sucessful? do - Result := db_handler.successful +-- Result := db_handler.successful end has_roles: BOOLEAN @@ -210,13 +210,7 @@ feature {NONE} -- Implementation post_execution -- Post database execution. do - if db_handler.successful then - set_successful - else - if attached db_handler.last_error then - set_last_error_from_handler (db_handler.last_error) - end - end + end end diff --git a/persistence/implementation/mysql/src/provider/user_data_provider.e b/persistence/implementation/mysql/src/provider/user_data_provider.e index a1ac47b..0d9b0bf 100644 --- a/persistence/implementation/mysql/src/provider/user_data_provider.e +++ b/persistence/implementation/mysql/src/provider/user_data_provider.e @@ -34,7 +34,6 @@ feature -- Status Report is_successful: BOOLEAN -- Is the last execution sucessful? do - Result := db_handler.successful end has_user: BOOLEAN @@ -311,13 +310,6 @@ feature {NONE} -- Implementation post_execution -- Post database execution. do - if db_handler.successful then - set_successful - else - if attached db_handler.last_error then - set_last_error_from_handler (db_handler.last_error) - end - end end end diff --git a/persistence/implementation/mysql/tests/util/clean_db.e b/persistence/implementation/mysql/tests/util/clean_db.e index 965465f..dce7176 100644 --- a/persistence/implementation/mysql/tests/util/clean_db.e +++ b/persistence/implementation/mysql/tests/util/clean_db.e @@ -24,6 +24,7 @@ feature do create l_parameters.make (0) + a_connection.begin_transaction -- Clean Profiles db_handler(a_connection).set_query (create {DATABASE_QUERY}.data_reader (Sql_delete_user_profiles, l_parameters)) @@ -72,6 +73,7 @@ feature db_handler(a_connection).set_query (create {DATABASE_QUERY}.data_reader (Rest_profiles_autoincrement, l_parameters)) db_handler(a_connection).execute_change + a_connection.commit end