Line data Source code
1 : /* File: data_change_notifier.c; Copyright and License: see below */
2 :
3 : #include "entity/data_id.h"
4 : #include "storage/data_change_notifier.h"
5 : #include "storage/data_change_message.h"
6 : #include "u8/u8_trace.h"
7 : #include "u8/u8_log.h"
8 : #include <glib-object.h>
9 : #include <string.h>
10 : #include <assert.h>
11 :
12 : static bool data_change_notifier_glib_signal_initialized = false;
13 : static guint data_change_notifier_glib_signal_id = 0;
14 : const char *DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME = "cfu_data_changed";
15 :
16 64 : void data_change_notifier_init ( data_change_notifier_t *this_ )
17 : {
18 64 : U8_TRACE_BEGIN();
19 :
20 64 : (*this_).num_listeners = 0;
21 64 : memset( (*this_).listener_array, '\0', sizeof( (*this_).listener_array ) );
22 64 : (*this_).stealth_mode = false;
23 :
24 : /* define a new signal */
25 64 : if ( ! data_change_notifier_glib_signal_initialized )
26 : {
27 1 : data_change_notifier_glib_signal_id = g_signal_new (
28 : DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME,
29 : G_TYPE_OBJECT,
30 : G_SIGNAL_RUN_FIRST,
31 : 0,
32 : NULL,
33 : NULL,
34 : g_cclosure_marshal_VOID__POINTER,
35 : G_TYPE_NONE,
36 : 1,
37 : G_TYPE_POINTER /* data_id_t*: id of the record that was created, updated or deleted */
38 : );
39 1 : data_change_notifier_glib_signal_initialized = true;
40 1 : U8_TRACE_INFO_INT( "g_signal_new(\"cfu_data_changed\") returned new signal id", data_change_notifier_glib_signal_id );
41 : }
42 :
43 64 : U8_TRACE_END();
44 64 : }
45 :
46 64 : void data_change_notifier_destroy ( data_change_notifier_t *this_ )
47 : {
48 64 : U8_TRACE_BEGIN();
49 :
50 64 : U8_TRACE_END();
51 64 : }
52 :
53 1970 : void data_change_notifier_emit_signal ( data_change_notifier_t *this_,
54 : data_change_event_type_t event_type,
55 : data_table_t table,
56 : data_row_t row_id,
57 : data_table_t parent_table,
58 : data_row_t parent_row_id )
59 : {
60 1970 : U8_TRACE_BEGIN();
61 :
62 1970 : if ( (*this_).stealth_mode )
63 : {
64 8 : U8_TRACE_INFO( "stealth mode: no signal sent" );
65 : }
66 : else
67 : {
68 : /* prepare */
69 : data_id_t modified_element_id;
70 : data_id_t parent_element_id;
71 : data_change_message_t message;
72 :
73 1962 : data_id_init( &modified_element_id, table, row_id );
74 1962 : data_id_init( &parent_element_id, parent_table, parent_row_id );
75 1962 : data_change_message_init( &message,
76 : event_type,
77 : modified_element_id,
78 : parent_element_id
79 : );
80 :
81 1962 : data_change_message_trace( &message );
82 :
83 : /* send messages */
84 1962 : for ( int32_t pos = 0; pos < (*this_).num_listeners; pos ++ )
85 : {
86 0 : U8_TRACE_INFO_INT( "g_signal_emit to listener", pos );
87 0 : g_signal_emit( (*this_).listener_array[pos], data_change_notifier_glib_signal_id, 0, &message );
88 : }
89 :
90 : /* clean up */
91 1962 : data_id_destroy( &modified_element_id );
92 1962 : data_id_destroy( &parent_element_id );
93 1962 : data_change_message_destroy( &message );
94 : }
95 :
96 1970 : U8_TRACE_END();
97 1970 : }
98 :
99 52 : u8_error_t data_change_notifier_add_listener ( data_change_notifier_t *this_, GObject *new_listener )
100 : {
101 52 : U8_TRACE_BEGIN();
102 52 : assert( NULL != new_listener );
103 52 : u8_error_t result = U8_ERROR_NONE;
104 :
105 : /* check for duplicates */
106 52 : bool duplicate = false;
107 1231 : for ( int32_t pos = 0; pos < (*this_).num_listeners; pos ++ )
108 : {
109 1179 : if( new_listener == (*this_).listener_array[pos] )
110 : {
111 1 : duplicate = true;
112 1 : result = U8_ERROR_INVALID_REQUEST;
113 1 : U8_LOG_ERROR( "duplicate call to data_change_notifier_add_listener for same listener." );
114 : }
115 : }
116 :
117 : /* if not a duplicate */
118 52 : if ( ! duplicate ) {
119 51 : if ( (*this_).num_listeners + 1 <= DATA_CHANGE_NOTIFIER_MAX_LISTENERS )
120 : {
121 50 : (*this_).listener_array[(*this_).num_listeners] = new_listener; /* possibly increases reference count */
122 50 : (*this_).num_listeners ++;
123 : }
124 : else
125 : {
126 1 : result = U8_ERROR_ARRAY_BUFFER_EXCEEDED;
127 1 : U8_LOG_ERROR( "data_change_notifier_add_listener has too many listeners." );
128 : }
129 : }
130 :
131 52 : U8_TRACE_END_ERR( result );
132 52 : return result;
133 : }
134 :
135 54 : u8_error_t data_change_notifier_remove_listener ( data_change_notifier_t *this_, GObject *no_listener )
136 : {
137 54 : U8_TRACE_BEGIN();
138 54 : assert( NULL != no_listener );
139 54 : u8_error_t result = U8_ERROR_NONE;
140 :
141 : /* search listener to remove */
142 54 : int32_t found_at_pos = -1; /* -1 means: not found */
143 1236 : for ( int32_t pos = 0; pos < (*this_).num_listeners; pos ++ )
144 : {
145 1182 : if( no_listener == (*this_).listener_array[pos] )
146 : {
147 50 : found_at_pos = pos;
148 : }
149 : }
150 :
151 : /* remove if found */
152 54 : if ( found_at_pos != -1 ) {
153 50 : U8_TRACE_INFO_INT( "unsubscribing from pos", found_at_pos );
154 50 : (*this_).listener_array[found_at_pos] = NULL;
155 50 : if ( found_at_pos + 1 != (*this_).num_listeners )
156 : {
157 24 : (*this_).listener_array[found_at_pos] = (*this_).listener_array[(*this_).num_listeners-1];
158 24 : (*this_).listener_array[(*this_).num_listeners-1] = NULL;
159 : }
160 50 : (*this_).num_listeners --;
161 : }
162 : else
163 : {
164 4 : result = U8_ERROR_INVALID_REQUEST;
165 4 : U8_LOG_ERROR( "data_change_notifier_remove_listener did not find listener to remove." );
166 : }
167 :
168 54 : U8_TRACE_END_ERR( result );
169 54 : return result;
170 : }
171 :
172 :
173 : /*
174 : Copyright 2016-2025 Andreas Warnke
175 :
176 : Licensed under the Apache License, Version 2.0 (the "License");
177 : you may not use this file except in compliance with the License.
178 : You may obtain a copy of the License at
179 :
180 : http://www.apache.org/licenses/LICENSE-2.0
181 :
182 : Unless required by applicable law or agreed to in writing, software
183 : distributed under the License is distributed on an "AS IS" BASIS,
184 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
185 : See the License for the specific language governing permissions and
186 : limitations under the License.
187 : */
|