Merge pull request #1551 from DOCGroup/plm_jira_333
[ACE_TAO.git] / TAO / examples / Event_Comm / Event_Comm_i.cpp
blob1f251648a07fb09e2e7295aa52ee2ea1539a4d62
1 #include "Event_Comm_i.h"
2 #include "ace/OS_NS_regex.h"
4 /**
5 * Keeps track of context information associated with
6 * a <Event_Comm::Consumer> entry.
7 */
8 class Consumer_Entry
10 public:
11 Consumer_Entry (Event_Comm::Consumer *consumer,
12 const char *filtering_criteria);
13 // Constructor.
15 ~Consumer_Entry (void);
16 // Descriptor.
18 // = Set/get filtering criteria.
19 void criteria (const char *criteria);
20 const char *criteria (void);
22 // = Set/get Event_Comm::Consumer object reference.
23 Event_Comm::Consumer *consumer (void);
24 void consumer (Event_Comm::Consumer *);
26 // = Set/get the compiled regular expression buffer.
27 const char *regexp (void);
28 void regexp (char *);
30 private:
31 const char *filtering_criteria_;
32 // String containing the filtering criteria.
34 char *compiled_regexp_;
35 // Compiled representation of the regular expression (see
36 // regexpr(3g)).
38 Event_Comm::Consumer_ptr consumer_;
39 // Object reference for the <Event_Comm::Consumer>.
42 // = Set/get filtering criteria.
44 void
45 Consumer_Entry::criteria (const char *criteria)
47 ACE_OS::free ((void *) this->filtering_criteria_);
48 ACE_ALLOCATOR (this->filtering_criteria_,
49 ACE_OS::strdup (criteria));
52 const char *
53 Consumer_Entry::criteria (void)
55 return this->filtering_criteria_;
58 // = Set/get Event_Comm::Consumer object reference.
60 Event_Comm::Consumer *
61 Consumer_Entry::consumer (void)
63 return this->consumer_;
66 void
67 Consumer_Entry::consumer (Event_Comm::Consumer *consumer)
69 this->consumer_ = consumer;
72 const char *
73 Consumer_Entry::regexp (void)
75 return this->compiled_regexp_;
78 void
79 Consumer_Entry::regexp (char *regexp)
81 ACE_OS::free ((void *) this->compiled_regexp_);
82 this->compiled_regexp_ = regexp;
85 Consumer_Entry::Consumer_Entry (Event_Comm::Consumer *consumer,
86 const char *filtering_criteria)
87 : filtering_criteria_ (0),
88 compiled_regexp_ (0),
89 consumer_ (consumer)
91 char *compile_buffer = 0;
93 this->criteria (filtering_criteria);
94 ACE_ASSERT (this->criteria ());
96 // Check for wildcard case first.
97 if (ACE_OS::strcmp (filtering_criteria, "") == 0)
98 ACE_ALLOCATOR (compile_buffer,
99 ACE_OS::strdup (""));
100 else
102 #if defined (ACE_HAS_REGEX)
103 // Compile the regular expression (the 0's cause ACE_OS::compile
104 // to allocate space).
105 compile_buffer = ACE_OS::compile (filtering_criteria, 0, 0);
106 #else
107 // Win32 does not support regular expression functions such as compile.
108 ACE_ALLOCATOR (compile_buffer,
109 ACE_OS::strdup (""));
110 #endif // #if defined (ACE_HAS_REGEX)
113 // Should throw an exception here!
114 ACE_ASSERT (compile_buffer != 0);
116 this->regexp (compile_buffer);
117 ACE_ASSERT (this->regexp () != 0);
119 // Increment the reference count since we are keeping a copy of
120 // this...
121 this->consumer_ = Event_Comm::Consumer::_duplicate (this->consumer_);
124 Consumer_Entry::~Consumer_Entry (void)
126 ACE_OS::free ((void *) this->filtering_criteria_);
127 ACE_OS::free ((void *) this->compiled_regexp_);
128 // Decrement the object reference count.
129 CORBA::release (this->consumer_);
132 Notifier_i::Notifier_i (size_t size)
133 : map_ (size)
135 // if platforms (such as win32) do not support the REGEXP functions
136 // such as <compile> and <step> then warn the user that the regular
137 // expression feature is not available.
138 #ifndef ACE_HAS_REGEX
139 ACE_DEBUG ((LM_DEBUG, "\n WARNING: This platform does not support \
140 the functions for regular expressions.\n\
141 The filtering criteria will not work.\n"));
142 #endif //#ifndef ACE_HAS_REGEX
145 // Add a new consumer to the table, being careful to check for
146 // duplicate entries. A consumer is considered a duplicate under the
147 // following circumstances:
149 // 1. It has the same object reference and the same filtering
150 // criteria.
151 // 2. It has the same object reference and its filtering criteria is
152 // "" (the wild card).
154 void
155 Notifier_i::subscribe (Event_Comm::Consumer_ptr consumer_ref,
156 const char *filtering_criteria)
158 ACE_DEBUG ((LM_DEBUG,
159 "in Notifier_i::subscribe for %x with filtering criteria \"%s\"\n",
160 consumer_ref,
161 filtering_criteria));
163 MAP_ITERATOR mi (this->map_);
165 // Try to locate an entry checking if the object references are
166 // equivalent. If we don't find the entry, or if the filtering
167 // criteria is different that is good news since we currently don't
168 // allow duplicates... @@ Should duplicates be allowed?
170 for (MAP_ENTRY *me = 0; mi.next (me) != 0; mi.advance ())
172 Consumer_Entry *nr_entry = me->int_id_;
174 // The <_is_equivalent> function checks if objects are the same.
175 // NOTE: this call might not behave well on other ORBs since
176 // <_is_equivalent> isn't guaranteed to differentiate object
177 // references.
179 // Check for a duplicate entry.
180 if (consumer_ref->_is_equivalent (me->ext_id_)
181 && (ACE_OS::strcmp (filtering_criteria,
182 "") == 0
183 || ACE_OS::strcmp (filtering_criteria,
184 nr_entry->criteria ()) == 0))
186 // Inform the caller that the <Event_Comm::Consumer> * is
187 // already being used.
189 throw Event_Comm::Notifier::CannotSubscribe (
190 "Duplicate consumer and filtering criteria found.\n");
194 // If we get this far then we didn't find a duplicate, so add the
195 // new entry!
196 Consumer_Entry *nr_entry;
197 ACE_NEW (nr_entry,
198 Consumer_Entry (consumer_ref,
199 filtering_criteria));
201 // Try to add new <Consumer_Entry> to the map.
202 if (this->map_.bind (nr_entry->consumer(), nr_entry) == -1)
204 // Prevent memory leaks.
205 delete nr_entry;
206 throw Event_Comm::Notifier::CannotSubscribe (
207 "Failed to add Consumer to internal map\n");
211 // Remove a consumer from the table.
213 void
214 Notifier_i::unsubscribe (Event_Comm::Consumer_ptr consumer_ref,
215 const char *filtering_criteria)
217 ACE_DEBUG ((LM_DEBUG,
218 "in Notifier_i::unsubscribe for %x\n",
219 consumer_ref));
221 Consumer_Entry *nr_entry = 0;
222 MAP_ITERATOR mi (this->map_);
223 int found = 0;
225 // Locate <Consumer_Entry> and free up resources. @@ Note, we don't
226 // properly handle deallocation of KEYS!
228 for (MAP_ENTRY *me = 0;
229 mi.next (me) != 0;
230 mi.advance ())
232 nr_entry = me->int_id_;
234 // The <_is_equivalent> function checks if objects are the same.
235 // NOTE: this call might not behave well on other ORBs since
236 // <_is_equivalent> isn't guaranteed to differentiate object
237 // references.
239 // Look for a match ..
240 if (consumer_ref->_is_equivalent (me->ext_id_)
241 && (ACE_OS::strcmp (filtering_criteria, "") == 0
242 || ACE_OS::strcmp (filtering_criteria,
243 nr_entry->criteria ()) == 0))
245 ACE_DEBUG ((LM_DEBUG,
246 "removed entry %x with criteria \"%s\"\n",
247 consumer_ref,
248 filtering_criteria));
249 found = 1;
250 // @@ This is a hack, we need a better approach!
251 if (this->map_.unbind (me->ext_id_,
252 nr_entry) == -1)
253 throw Event_Comm::Notifier::CannotUnsubscribe (
254 "Internal map unbind failed.");
255 else
256 delete nr_entry;
260 if (found == 0)
261 throw Event_Comm::Notifier::CannotUnsubscribe (
262 "The Consumer and filtering criteria were not found.");
265 // Disconnect all the consumers, giving them the <reason>.
267 void
268 Notifier_i::disconnect (const char *reason)
270 ACE_DEBUG ((LM_DEBUG,
271 "in Notifier_i::send_disconnect = %s\n",
272 reason));
274 MAP_ITERATOR mi (this->map_);
275 int count = 0;
277 // Notify all the consumers, taking into account the filtering
278 // criteria.
280 for (MAP_ENTRY *me = 0;
281 mi.next (me) != 0;
282 mi.advance ())
284 Event_Comm::Consumer_ptr consumer_ref =
285 me->ext_id_;
287 ACE_ASSERT (consumer_ref != 0);
288 ACE_DEBUG ((LM_DEBUG,
289 "disconnecting client %x\n",
290 consumer_ref));
293 consumer_ref->disconnect (reason);
295 catch (const CORBA::Exception& ex)
297 ex._tao_print_exception ("Unexpected exception\n");
300 delete me->int_id_;
301 count++;
304 this->map_.close ();
306 if (count == 1)
307 ACE_DEBUG ((LM_DEBUG,
308 "there was 1 consumer\n"));
309 else
310 ACE_DEBUG ((LM_DEBUG,
311 "there were %d consumers\n",
312 count));
315 // Notify all consumers whose filtering criteria match the event.
317 void
318 Notifier_i::push (const Event_Comm::Event &event)
320 ACE_DEBUG ((LM_DEBUG,
321 "in Notifier_i::send_notification = %s\n",
322 (const char *) event.tag_));
323 MAP_ITERATOR mi (this->map_);
324 int count = 0;
326 // Notify all the consumers.
328 for (MAP_ENTRY *me = 0; mi.next (me) != 0; mi.advance ())
330 Event_Comm::Consumer_ptr consumer_ref = me->int_id_->consumer ();
331 ACE_ASSERT (consumer_ref != 0);
333 #if defined (ACE_HAS_REGEX)
334 char *regexp = const_cast<char *> (me->int_id_->regexp ());
335 ACE_ASSERT (regexp);
337 const char *criteria = me->int_id_->criteria ();
338 ACE_ASSERT (criteria);
340 // Do a regular expression comparison to determine matching.
341 if (ACE_OS::strcmp ("", criteria) == 0 // Everything matches the wildcard.
342 || ACE_OS::step (event.tag_, regexp) != 0)
343 #endif // #if defined (ACE_HAS_REGEX)
344 // if ACE_HAS_REGEX has not been defined,
345 // let everything through.
347 ACE_DEBUG ((LM_DEBUG,
348 "string %s matched regexp \"%s\" for client %x\n",
349 (const char *) event.tag_,
350 me->int_id_->criteria (),
351 consumer_ref));
354 consumer_ref->push (event);
356 catch (const CORBA::Exception& ex)
358 ex._tao_print_exception ("Unexpected exception\n");
359 continue;
361 count++;
365 if (count == 1)
366 ACE_DEBUG ((LM_DEBUG,
367 "there was 1 consumer\n"));
368 else
369 ACE_DEBUG ((LM_DEBUG,
370 "there were %d consumers\n",
371 count));
374 // -------------
376 ShutdownCallback::~ShutdownCallback (void)
380 // -------------
382 //FUZZ: disable check_for_lack_ACE_OS
383 Consumer_i::Consumer_i (void)
384 : shutdown (0)
387 //FUZZ: enable check_for_lack_ACE_OS
389 Consumer_i::~Consumer_i (void)
393 // Inform the <Event_Comm::Consumer> that <event> has
394 // occurred.
396 void
397 Consumer_i::push (const Event_Comm::Event &event)
399 const char *tmpstr = event.tag_;
401 ACE_DEBUG ((LM_DEBUG,
402 "**** got notification = %s\n",
403 tmpstr));
406 // Disconnect the <Event_Comm::Consumer> from the
407 // <Event_Comm::Notifier>.
409 void
410 Consumer_i::disconnect (const char *reason)
412 ACE_DEBUG ((LM_DEBUG,
413 "**** got disconnected due to %s\n",
414 reason));
416 ACE_ASSERT (shutdown != 0);
418 shutdown->close ();
421 void
422 Consumer_i::set (ShutdownCallback *_shutdown)
424 shutdown = _shutdown;