Inter process communication with $SYSTEM.Event
Tags: beginners, codesnippet, programming, coding
Published: 2024-02-13 18:37:33

<p><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">Hi, developers!</span></span></span></span></span></span></p>
<p><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">Currently, I'm working on a project that requires highly dynamic event management. In the context of the Java programming language, my first instinct should be to opt for the "Observer Pattern", which is an approach to managing interactions between objects by establishing a notification mechanism. It allows multiple observers to react to changes in the state of a subject autonomously, promoting code flexibility and modularity. If you are not familiar with this design pattern, check out </span></span></span></span></span></span><a href="https://fr.wikipedia.org/wiki/Observateur_(patron_de_conception)" style="text-decoration:none"><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#1155cc"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:underline"><span style="-webkit-text-decoration-skip:none"><span style="text-decoration-skip-ink:none">Wikipedia</span></span></span></span></span></span></span></span></a><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none"> to find more information about it.</span></span></span></span></span></span></p>
<p style="line-height:1.38"><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none"><span style="border:none"><span style="display:inline-block"><span style="overflow:hidden"><span style="width:602px"><span style="height:249px"><img height="249" src="https://lh5.googleusercontent.com/6d0yEkLCQnSG_bnQfS5NX1MteTk8svDAFJ59fMXFAtrGZYt1toa-bzd9RsU2P0Yzm5GHZfoVQc6bMZokgr-cG8tbyrwEpMWN88ELy4KoCnB6R8-9rbeipVzVZHI-__BrPE7VYkG6FREAZIC1IU-GWGo" width="602"></span></span></span></span></span></span></span></span></span></span></span><br><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">While it's natural and commonly used in certain programming languages as Java and C++, in ObjectScript, it's quite a different story.</span></span></span></span></span></span></p>

<p><!--break--><br><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">These languages differ significantly.</span></span></span></span></span></span><span style="font-size:10.5pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Roboto,sans-serif"><span style="color:#444746"><span style="background-color:#ffffff"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">While Java allows you to start threads, in ObjectScript, you can only launch new processes. This distinction is noticeable in several aspects:</span></span></span></span></span></span></span></p>
<ul>
<li><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none"><strong>Threads</strong>: sshare the same memory, which makes it easier to communicate and share data between them. However, this can also lead to concurrency issues if synchronization is not managed properly.</span></span></span></span></span></span></li>
</ul>
<p>&nbsp;</p>
<ul>
<li><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none"><strong>Processes</strong>: are independent executions with their own memory space. They offer complete isolation from each other, meaning that one process cannot directly access another one's memory. Due to their isolation, processes are safer in case an error occurs because a faulty process will not be able to affect other system processes. However, communication between them is more complex than between threads since it requires such inter-process communication (IPC) mechanisms as sockets, pipes, or message queues.</span></span></span></span></span></span></li>
</ul>
<p><br><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">This fundamental difference calls for a different approach. However, is it not conceivable to develop a library fast enough and solve this problem? This is the problem I have faced, and I wish to present my solution to you now. As usual for my articles, you will find the source code on a GitHub repository and a package available on Open Exchange.</span></span></span></span></span></span></p>
<p><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">The goal is not to replicate the Observer Pattern but to develop a quick fix to facilitate inter-process communication in order to notify processes waiting for an event. </span></span></span></span></span></span><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">Let's take as an example a process that handles patient creation.&nbsp; In this scenario, we could represent the following sequence of activities:</span></span></span></span></span></span></p>

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p37ijoqewle3fw4cwvyd.png)
<p style="line-height:1.656; margin-top:16px; margin-bottom:16px"><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">Process A informs the "Patient" event manager and is responsible for sending a message to all registered observers.</span></span></span></span></span></span><span style="font-size:10.5pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Roboto,sans-serif"><span style="color:#444746"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">To set this up, it is essential to determine how to adjust inter-process communication.</span></span></span></span></span></span><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none"> Upon consulting the documentation, I quickly discovered a perfect class for solving this issue: $SYSTEM.Event.</span></span></span></span></span></span></p>
<p style="line-height:1.656; margin-top:16px; margin-bottom:16px"><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">You can perform a brief test by opening two IRIS terminal sessions. The first one will be intended to create the resource and listen to incoming messages, while the second one will be used to send notifications.</span></span></span></span></span></span></p>

<table border="1" cellpadding="1" cellspacing="1" style="width: 500px;">
<tbody>
<tr>
<td><span style="overflow:hidden"><span style="overflow-wrap:break-word"><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">Session en écoute</span></span></span></span></span></span></span></span></td>
<td><span style="overflow:hidden"><span style="overflow-wrap:break-word"><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:'Courier New',monospace"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">Session qui notifie</span></span></span></span></span></span></span></span></td>
</tr>
<tr>
<td>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Create(<span class="hljs-string">"MyResource"</span>)

<span class="hljs-keyword">Set</span> message = <span class="hljs-built_in">$SYSTEM</span>.Event.WaitMsg(<span class="hljs-string">"MyResource"</span>, <span class="hljs-number">10</span>)</code></pre>
<p>&nbsp;</p></td>
<td>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Signal(<span class="hljs-string">"MyResource"</span>,<span class="hljs-string">"Hello, from PID:"</span>_<span class="hljs-built_in">$Job</span>)



</code></pre>
<p>&nbsp;</p></td>
</tr>
</tbody></table>
<div>&nbsp;</div>
<p style="line-height:1.38"><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">After sending the signal, the content of the "message" variable will be as follows:</span></span></span></span></span></span></p>

<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-built_in">$lb</span>(<span class="hljs-number">1</span>,<span class="hljs-string">"Hello, this is a message from PID:710"</span>)</code></pre>
<p><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">The first position is a return code:</span></span></span></span></span></span></p>
<ul>
<li><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">1: Message received.</span></span></span></span></span></span></li>
<li><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">0: Timeout (10 seconds in the example above).</span></span></span></span></span></span></li>
<li><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">-1: Error situation "MyResource" resource was removed.</span></span></span></span></span></span></li>
</ul>
<p><br><em><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none"><strong>Note</strong>: It's not mandatory to create the resource with $SYSTEM.Event.Create; in this case waiting can be done with the next line:</span></span></span></span></span></span></em></p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Set</span> message = <span class="hljs-built_in">$SYSTEM</span>.Event.WaitMsg(<span class="hljs-string">""</span>,<span class="hljs-number">10</span>)</code></pre>
<p><span style="font-size:11.5pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Roboto,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">The signal must specify the PID (Process ID) of the listening process:</span></span></span></span></span></span></p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-built_in">$SYSTEM</span>.Event.Signal(&lt;pid&gt;, <span class="hljs-string">"Hello from:"</span>_<span class="hljs-built_in">$Job</span>)</code></pre>
<p><br>In this example, we transmitted a simple string because it is impossible to pass objects directly. As explained earlier in this article, a process cannot access another process's memory, making it impossible to transmit object references. However, thanks to the %DynamicObject class, we can easily convert objects to JSON strings and vice versa. Therefore, we can do the following:</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Signal(<span class="hljs-string">"MyResource"</span>,{<span class="hljs-string">"PID"</span>:(<span class="hljs-built_in">$JOB</span>),<span class="hljs-string">"Msg"</span>:<span class="hljs-string">"Hello!"</span>}.<span class="hljs-built_in">%ToJSON</span>())

<span class="hljs-comment">; After receiving a message: </span>
<span class="hljs-keyword">Set</span> object = {}.<span class="hljs-built_in">%FromJSON</span>(<span class="hljs-built_in">$ListGet</span>(message,<span class="hljs-number">2</span>))
</code></pre>
<p>Furthermore, if you are working with a recent version of IRIS, you have the option to extend your existing classes using %JSON.Adaptor and easily export their instances with the %JSONExportToString method.</p>
<p>By combining the use of $SYSTEM.Event and %DynamicObject, you can establish inter-process communication in just a few lines, sending both simple messages and objects.</p>
<p>It is important to note that while $SYSTEM.Event is very convenient, it will not work on an ECP (Enterprise Cache Protocol) system, as mentioned in the official documentation:</p>
<p style="line-height:1.656; margin-bottom:11px"><em><span style="font-size:10.5pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Consolas,sans-serif"><span style="color:#333333"><span style="background-color:#f5f5f5"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">“There is no networking support for these functions - processes can only wait on and awaken resources on the same system.”</span></span></span></span></span></span></span></em></p>

<p>It is imperative to exercise great caution when using $SYSTEM.Event because it relies on "SharedMemory," an essential but limited space for system operation. If a process sends a large number of signals, and the destination process cannot deal with them quickly enough, the signal queue will grow, potentially leading to a system crash. Below there is an overview of what you might find in the "messages.log" file:</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-number">10</span>/<span class="hljs-number">04</span>/<span class="hljs-number">23</span>-<span class="hljs-number">08</span>:<span class="hljs-number">33</span>:<span class="hljs-number">47</span>:<span class="hljs-number">501</span> (<span class="hljs-number">1057</span>) <span class="hljs-number">1</span> [Generic.Event] SMH Surrender Stage <span class="hljs-number">1</span> started.
<span class="hljs-number">10</span>/<span class="hljs-number">04</span>/<span class="hljs-number">23</span>-<span class="hljs-number">08</span>:<span class="hljs-number">33</span>:<span class="hljs-number">47</span>:<span class="hljs-number">542</span> (<span class="hljs-number">1057</span>) <span class="hljs-number">1</span> [Generic.Event] SMH Surrender Stage <span class="hljs-number">2</span> started.
<span class="hljs-number">10</span>/<span class="hljs-number">04</span>/<span class="hljs-number">23</span>-<span class="hljs-number">08</span>:<span class="hljs-number">33</span>:<span class="hljs-number">48</span>:<span class="hljs-number">547</span> (<span class="hljs-number">818</span>) <span class="hljs-number">2</span> [Utility.Event] ISCLOG: WorkMgr appendError: Error ns=<span class="hljs-built_in">%SYS</span> rtn=<span class="hljs-built_in">%SYS.WorkQueueMgr</span>  data=<span class="hljs-built_in">$lb</span>(<span class="hljs-string">"rc"</span>,<span class="hljs-string">"0 "</span>_<span class="hljs-built_in">$lb</span>(<span class="hljs-built_in">$lb</span>(<span class="hljs-number">5002</span>,<span class="hljs-string">"&lt;STORE&gt;RunDaemon+167^%SYS.WorkQueueMgr"</span>,,,,,,,,<span class="hljs-built_in">$lb</span>(,<span class="hljs-string">"%SYS"</span>,<span class="hljs-built_in">$lb</span>(<span class="hljs-string">"D^RunDaemon+167^%SYS.WorkQueueMgr +1"</span>,<span class="hljs-string">"D^StartWorkDaemon+4^STU +1"</span>))))<span class="hljs-comment">/* ERROR #5002: ObjectScript error: &lt;STORE&gt;RunDaemon+167^%SYS.WorkQueueMgr */</span>,<span class="hljs-string">"group"</span>,,<span class="hljs-string">"stack"</span>,<span class="hljs-built_in">$lb</span>(<span class="hljs-string">"d^RunDaemon+226^%SYS.WorkQueueMgr^1"</span>,<span class="hljs-string">"d^StartWorkDaemon+4^STU^1"</span>,<span class="hljs-string">"d^^^0"</span>),<span class="hljs-string">"$zu(56,2)"</span>,<span class="hljs-string">"$Id: //iris/2023.2.0/kernel/common/src/events.c#1 $ 568 4"</span>)
<span class="hljs-number">10</span>/<span class="hljs-number">04</span>/<span class="hljs-number">23</span>-<span class="hljs-number">08</span>:<span class="hljs-number">34</span>:<span class="hljs-number">00</span>:<span class="hljs-number">202</span> (<span class="hljs-number">1033</span>) <span class="hljs-number">2</span> [Utility.Event] [SYSTEM MONITOR] SMHState Alert: Shared Memory Heap state Troubled
<span class="hljs-number">10</span>/<span class="hljs-number">04</span>/<span class="hljs-number">23</span>-<span class="hljs-number">08</span>:<span class="hljs-number">34</span>:<span class="hljs-number">00</span>:<span class="hljs-number">978</span> (<span class="hljs-number">1032</span>) <span class="hljs-number">0</span> [Utility.Event] Task Manager Error from CheckSchedule - Error <span class="hljs-number">0</span>
<span class="hljs-number">10</span>/<span class="hljs-number">04</span>/<span class="hljs-number">23</span>-<span class="hljs-number">08</span>:<span class="hljs-number">34</span>:<span class="hljs-number">51</span>:<span class="hljs-number">308</span> (<span class="hljs-number">1063</span>) <span class="hljs-number">2</span> [Utility.Event] ISCLOG: CSPServer  Error displaying login page <span class="hljs-built_in">$ZE</span>= ns=<span class="hljs-built_in">%SYS</span> rtn=<span class="hljs-built_in">%SYS.cspServer</span>
<span class="hljs-number">10</span>/<span class="hljs-number">04</span>/<span class="hljs-number">23</span>-<span class="hljs-number">08</span>:<span class="hljs-number">35</span>:<span class="hljs-number">00</span>:<span class="hljs-number">290</span> (<span class="hljs-number">1033</span>) <span class="hljs-number">2</span> [Utility.Event] [SYSTEM MONITOR] SMHPercentFull Alert: SMHPercentFull = <span class="hljs-number">100</span>, <span class="hljs-number">100</span>, <span class="hljs-number">100</span> (Max value is <span class="hljs-number">98</span>).
</code></pre>
<p>To prevent such a situation, you can opt for bidirectional communication. When a signal gets sent, the process waits for an “acknowledgement” before proceeding, as illustrated in the following example:</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Create(<span class="hljs-string">"MyResource"</span>)
<span class="hljs-keyword">Write</span> !,<span class="hljs-string">"Type &lt; ctrl+c &gt; to stop listening."</span>
<span class="hljs-keyword">Try</span> {
    <span class="hljs-keyword">For</span>  {
        <span class="hljs-keyword">Set</span> result = <span class="hljs-built_in">$SYSTEM</span>.Event.WaitMsg(<span class="hljs-string">"MyResource"</span>,<span class="hljs-number">10</span>)
        <span class="hljs-keyword">Set</span> code = <span class="hljs-built_in">$ListGet</span>(result,<span class="hljs-number">1</span>)
        <span class="hljs-keyword">Continue</span>:code=<span class="hljs-number">0</span>
        <span class="hljs-keyword">Quit</span>:code=-<span class="hljs-number">1</span>
        <span class="hljs-keyword">Set</span> event = {}.<span class="hljs-built_in">%FromJSON</span>(<span class="hljs-built_in">$ListGet</span>(result,<span class="hljs-number">2</span>))
        <span class="hljs-keyword">Write</span> !, <span class="hljs-string">"Content : "</span>, event.Content
        <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Signal(event.PID) <span class="hljs-comment">; Send aknowledgement</span>
    }
} <span class="hljs-keyword">Catch</span> ex {
    <span class="hljs-keyword">If</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Defined(<span class="hljs-string">"MyResource"</span>) {
        <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Clear(<span class="hljs-string">"MyResource"</span>)
        <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Delete(<span class="hljs-string">"MyResource"</span>)
    }
}
</code></pre>
<p>&nbsp;</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">For</span> i=<span class="hljs-number">1</span>:<span class="hljs-number">1</span>:<span class="hljs-number">100</span> {
    <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Signal(<span class="hljs-string">"MyResource"</span>,{<span class="hljs-string">"PID"</span>:(<span class="hljs-built_in">$Job</span>),<span class="hljs-string">"Content"</span>:<span class="hljs-string">"Hello!"</span>})
    <span class="hljs-keyword">Set</span> code = <span class="hljs-built_in">$SYSTEM</span>.Event.Wait(<span class="hljs-string">""</span>,<span class="hljs-number">3</span>) <span class="hljs-comment">; Wait acknowledgement</span>
    <span class="hljs-keyword">If</span> code &lt; <span class="hljs-number">1</span> {
        <span class="hljs-keyword">Write</span> <span class="hljs-string">"Something went wrong."</span>
        <span class="hljs-keyword">If</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Defined(<span class="hljs-string">"MyResource"</span>) {
            <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Clear(<span class="hljs-string">"MyResource"</span>)
            <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Delete(<span class="hljs-string">"MyResource"</span>)
        }
        <span class="hljs-keyword">Quit</span>
    }
}</code></pre>
<p>If you adopt this approach, your process's queue will never contain more than one message at a time. Also, make sure that you always perform a "Clear" operation before "Delete" to avoid leaving unprocessed messages in the queue indefinitely.</p>
<p>Now that we have laid the groundwork, we can implement an "abstract" base class with the listener role.</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Class</span> dc.ipcutils.ListenerAbstract <span class="hljs-keyword">Extends</span> <span class="hljs-built_in">%RegisteredObject</span>
{

<span class="hljs-keyword">Parameter</span> EVENTTYPE<span class="hljs-comment">;</span>
<span class="hljs-keyword">Parameter</span> WAITTIMEOUT = <span class="hljs-number">10</span><span class="hljs-comment">;</span>
<span class="hljs-keyword">Parameter</span> VERBOSE = <span class="hljs-number">0</span><span class="hljs-comment">;</span>
<span class="hljs-keyword">Property</span> ResourceName <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span> [ Internal ]<span class="hljs-comment">;</span>
<span class="hljs-keyword">Property</span> Verbose <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Boolean</span> [ InitialExpression = {<span class="hljs-built_in">$Get</span>(<span class="hljs-built_in">%zverbose</span>,..#VERBOSE)}, Internal ]<span class="hljs-comment">;</span>
<span class="hljs-keyword">Property</span> EventType <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span> [ InitialExpression = {..#EVENTTYPE} ]<span class="hljs-comment">;</span>
<span class="hljs-keyword">Property</span> Event <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span><span class="hljs-comment">;</span>
<span class="hljs-comment">/// could be a string or a dynamicobject</span>
<span class="hljs-keyword">Property</span> Data<span class="hljs-comment">;</span>
<span class="hljs-keyword">Property</span> Context <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span><span class="hljs-comment">;</span>
<span class="hljs-keyword">Property</span> LastState <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Integer</span> [ InitialExpression = <span class="hljs-number">0</span> ]<span class="hljs-comment">;</span>
Method OnStartListen(Context <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span> = {}) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    <span class="hljs-keyword">Set</span> <span class="hljs-built_in">..ResourceName</span> = <span class="hljs-built_in">..GenResourceName</span>()
    <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Create(<span class="hljs-built_in">..ResourceName</span>), <span class="hljs-keyword">##class</span>(dc.ipcutils.Manager).Subscribe(##this, Context)
    <span class="hljs-keyword">Write</span>:<span class="hljs-built_in">..Verbose</span> !, <span class="hljs-built_in">$zdt</span>(<span class="hljs-built_in">$h</span>,<span class="hljs-number">3</span>,<span class="hljs-number">1</span>), <span class="hljs-string">" + Listening "</span>, <span class="hljs-built_in">..EventType</span>, <span class="hljs-string">" with resourcename "</span>, <span class="hljs-built_in">..ResourceName</span>, <span class="hljs-string">" started."</span>
    <span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$OK</span>
}

Method Listen() <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    <span class="hljs-keyword">Set</span> sc = <span class="hljs-built_in">$$$OK</span>
    <span class="hljs-built_in">$$$QuitOnError</span>(<span class="hljs-built_in">..OnStartListen</span>())
    
    <span class="hljs-keyword">Try</span> {
        <span class="hljs-keyword">For</span>  <span class="hljs-keyword">If</span> <span class="hljs-built_in">..Wait</span>() = -<span class="hljs-number">1</span> <span class="hljs-built_in">$$$ThrowStatus</span>(<span class="hljs-built_in">$$$ERROR</span>(<span class="hljs-built_in">$$$GeneralError</span>,<span class="hljs-built_in">$$$FormatText</span>(<span class="hljs-string">"Resource %1 deleted."</span>,<span class="hljs-built_in">..ResourceName</span>)))
    } <span class="hljs-keyword">Catch</span> Ex {
        <span class="hljs-keyword">If</span> Ex.Name '[ <span class="hljs-string">"&lt;INTERRUPT&gt;"</span> <span class="hljs-keyword">Set</span> sc = Ex.AsStatus()
    }
    
    <span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$ADDSC</span>(sc,<span class="hljs-built_in">..OnStopListen</span>())
}

Method Wait(
	TimeOut <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Integer</span> = {..#WAITTIMEOUT},
	sc <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span> = {<span class="hljs-built_in">$$$OK</span>}) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Integer</span>
{
    <span class="hljs-keyword">Do</span>:<span class="hljs-built_in">..LastState</span>=<span class="hljs-number">1</span> <span class="hljs-built_in">..SendAck</span>() <span class="hljs-comment">; We have to send a ack before waiting a new incoming message.</span>
    <span class="hljs-keyword">Set</span> result = <span class="hljs-built_in">$SYSTEM</span>.Event.WaitMsg(<span class="hljs-built_in">..ResourceName</span>, TimeOut)
    <span class="hljs-keyword">Set</span> <span class="hljs-built_in">..LastState</span> = <span class="hljs-built_in">$ListGet</span>(result,<span class="hljs-number">1</span>)

    <span class="hljs-keyword">If</span> <span class="hljs-built_in">..LastState</span> &lt; <span class="hljs-number">1</span> <span class="hljs-keyword">Quit</span> <span class="hljs-built_in">..LastState</span>
    <span class="hljs-keyword">Set</span> <span class="hljs-built_in">..Event</span> = {}.<span class="hljs-built_in">%FromJSON</span>(<span class="hljs-built_in">$ListGet</span>(result,<span class="hljs-number">2</span>))
    <span class="hljs-keyword">Set</span> <span class="hljs-built_in">..Data</span> = <span class="hljs-built_in">..Event</span>.Data
    <span class="hljs-keyword">Set</span> <span class="hljs-built_in">..Context</span> = <span class="hljs-built_in">..Event</span>.Context
    
    <span class="hljs-keyword">Do</span> <span class="hljs-built_in">..Event</span>.<span class="hljs-built_in">%Remove</span>(<span class="hljs-string">"Data"</span>)
    <span class="hljs-keyword">Do</span> <span class="hljs-built_in">..Event</span>.<span class="hljs-built_in">%Remove</span>(<span class="hljs-string">"Context"</span>)

    <span class="hljs-keyword">Try</span> {
        <span class="hljs-keyword">Do</span> <span class="hljs-built_in">..Update</span>(<span class="hljs-built_in">..Event</span>, <span class="hljs-built_in">..Data</span>, <span class="hljs-built_in">..Context</span>)
    } <span class="hljs-keyword">Catch</span> (ex) {
        <span class="hljs-keyword">Set</span> sc = ex.AsStatus()
        <span class="hljs-keyword">Set</span> <span class="hljs-symbol">^Listener</span>.Err(<span class="hljs-string">"last"</span>) = <span class="hljs-built_in">$zdt</span>(<span class="hljs-built_in">$h</span>,<span class="hljs-number">3</span>,<span class="hljs-number">1</span>)_<span class="hljs-string">" "</span>_<span class="hljs-built_in">$SYSTEM</span>.Status.GetOneErrorText(sc)
    }

    <span class="hljs-keyword">Quit</span> <span class="hljs-built_in">..LastState</span>
}

Method SendAck()
{
    <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Signal(<span class="hljs-built_in">..Event</span>.PIDSource,<span class="hljs-built_in">..Event</span>.<span class="hljs-built_in">%ToJSON</span>())
}

Method Update(
	EventObject <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>,
	Data <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>,
	Context <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    <span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$OK</span>
}

Method WaitEvent(
	Output Event <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>,
	TimeOut <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Integer</span> = {..#WAITTIMEOUT}) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Integer</span>
{
    <span class="hljs-keyword">Set</span> result = <span class="hljs-built_in">$SYSTEM</span>.Event.WaitMsg(<span class="hljs-built_in">..ResourceName</span>, TimeOut), returnCode = <span class="hljs-built_in">$ListGet</span>(result,<span class="hljs-number">1</span>), Event = <span class="hljs-string">""</span>
    <span class="hljs-keyword">If</span> returnCode &lt; <span class="hljs-number">1</span> <span class="hljs-keyword">Quit</span> returnCode
    
    <span class="hljs-keyword">Set</span> <span class="hljs-built_in">..Event</span> = {}.<span class="hljs-built_in">%FromJSON</span>(<span class="hljs-built_in">$ListGet</span>(result,<span class="hljs-number">2</span>))
    <span class="hljs-keyword">Set</span> <span class="hljs-built_in">..Data</span> = Event.Data
    <span class="hljs-keyword">Set</span> <span class="hljs-built_in">..Context</span> = Event.Context
    <span class="hljs-keyword">Do</span> <span class="hljs-built_in">..Event</span>.<span class="hljs-built_in">%Remove</span>(<span class="hljs-string">"Data"</span>), <span class="hljs-built_in">..Event</span>.<span class="hljs-built_in">%Remove</span>(<span class="hljs-string">"Context"</span>)

    <span class="hljs-keyword">Quit</span> returnCode
}

Method OnStopListen(Context <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span> = {}) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    <span class="hljs-keyword">Write</span>:<span class="hljs-built_in">..Verbose</span> !, <span class="hljs-built_in">$zdt</span>(<span class="hljs-built_in">$h</span>,<span class="hljs-number">3</span>,<span class="hljs-number">1</span>), <span class="hljs-string">" - Listening "</span>, <span class="hljs-built_in">..EventType</span>, <span class="hljs-string">" with resourcename "</span>, <span class="hljs-built_in">..ResourceName</span>, <span class="hljs-string">" has been STOPPED."</span>
    <span class="hljs-keyword">Do</span>:<span class="hljs-built_in">$SYSTEM</span>.Event.Defined(<span class="hljs-built_in">..ResourceName</span>) <span class="hljs-built_in">$SYSTEM</span>.Event.Clear(<span class="hljs-built_in">..ResourceName</span>), <span class="hljs-built_in">$SYSTEM</span>.Event.Delete(<span class="hljs-built_in">..ResourceName</span>)
    <span class="hljs-keyword">Quit</span> <span class="hljs-keyword">##class</span>(dc.ipcutils.Manager).UnSubscribe(##this, Context)
}

Method GenResourceName() <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span> [ CodeMode = expression, Private ]
{
<span class="hljs-built_in">$Translate</span>(<span class="hljs-built_in">$SYSTEM</span>.Encryption.Base64Encode(<span class="hljs-built_in">$Job</span>_<span class="hljs-built_in">$zcrc</span>(<span class="hljs-built_in">..EventType</span>_<span class="hljs-built_in">$ZDT</span>(<span class="hljs-built_in">$H</span>,<span class="hljs-number">3</span>,<span class="hljs-number">1</span>),<span class="hljs-number">7</span>)),<span class="hljs-string">"="</span>)
}

}</code></pre>
<p>Listeners need to register with a "Manager." Let's move on to writing this manager, which will handle the functions of subscribing and unsubscribing as well as notifications:</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos">Include ipcutils

<span class="hljs-keyword">Class</span> dc.ipcutils.Manager
{

<span class="hljs-keyword">Parameter</span> ACKTIMEOUT = <span class="hljs-number">3</span><span class="hljs-comment">;</span>
<span class="hljs-keyword">ClassMethod</span> Subscribe(
    Observer <span class="hljs-keyword">As</span> dc.ipcutils.ListenerAbstract,
    Context <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span> = {}) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    <span class="hljs-keyword">Set</span> <span class="hljs-built_in">$$$Subscribed</span>(Observer.EventType, <span class="hljs-built_in">$Classname</span>(Observer), Observer.ResourceName) = <span class="hljs-built_in">$ListBuild</span>(Observer.EventType,Observer.ResourceName,<span class="hljs-built_in">$zdt</span>(<span class="hljs-built_in">$H</span>,<span class="hljs-number">3</span>,<span class="hljs-number">1</span>),<span class="hljs-built_in">$Job</span>,Context.<span class="hljs-built_in">%ToJSON</span>())
    <span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$OK</span>
}

<span class="hljs-keyword">ClassMethod</span> UnSubscribe(
    Observer <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span>,
    Context <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    <span class="hljs-keyword">Kill</span> <span class="hljs-built_in">$$$Subscribed</span>(Observer.EventType, <span class="hljs-built_in">$Classname</span>(Observer), Observer.ResourceName)
    <span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$OK</span>
}

<span class="hljs-keyword">ClassMethod</span> Notify(
    Event <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span>,
    Data <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    #def1arg ResourceName(<span class="hljs-built_in">%val</span>)     <span class="hljs-built_in">$QSubscript</span>(<span class="hljs-built_in">%val</span>,<span class="hljs-number">3</span>)
    #def1arg Context(<span class="hljs-built_in">%val</span>)          {}.<span class="hljs-built_in">%FromJSON</span>(<span class="hljs-built_in">$ListGet</span>(<span class="hljs-built_in">%val</span>,<span class="hljs-number">5</span>))
    
    <span class="hljs-keyword">#dim</span> NotifyObject <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span> = <span class="hljs-keyword">##class</span>(dc.ipcutils.Manager).GenEventObject(Event)
    
    <span class="hljs-keyword">Set</span> sc = <span class="hljs-built_in">$$$OK</span>
    <span class="hljs-keyword">Set</span> node = <span class="hljs-built_in">$Name</span>(<span class="hljs-built_in">$$$Subscribed</span>(NotifyObject.EventType))
    <span class="hljs-keyword">For</span>  {
        <span class="hljs-keyword">Set</span> node = <span class="hljs-built_in">$Query</span>(@node,<span class="hljs-number">1</span>,value)
        <span class="hljs-keyword">Quit</span>:node=<span class="hljs-string">""</span>||(NotifyObject.EventType'=<span class="hljs-built_in">$QSubscript</span>(node,<span class="hljs-number">1</span>))
        
        <span class="hljs-keyword">Set</span> resourceName = <span class="hljs-built_in">$$$ResourceName</span>(node)
        <span class="hljs-keyword">Set</span> NotifyObject.Context = <span class="hljs-built_in">$$$Context</span>(value), NotifyObject.Data = Data

        <span class="hljs-comment">; check if the resource exists AND if process that creates the resource still exists!        </span>
        <span class="hljs-keyword">If</span> '<span class="hljs-built_in">$System</span>.Event.Defined(resourceName) || '<span class="hljs-built_in">$Data</span>(^<span class="hljs-built_in">$JOB</span>(<span class="hljs-built_in">$ListGet</span>(value, <span class="hljs-number">4</span>))) <span class="hljs-keyword">Do</span> UnSubscribe <span class="hljs-keyword">Continue</span>
        <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Event.Signal(resourceName, NotifyObject.<span class="hljs-built_in">%ToJSON</span>())
        <span class="hljs-keyword">Do</span> WaitAck

        <span class="hljs-keyword">Do</span> NotifyObject.<span class="hljs-built_in">%Remove</span>(<span class="hljs-string">"Context"</span>), NotifyObject.<span class="hljs-built_in">%Remove</span>(<span class="hljs-string">"Data"</span>)
    }
    <span class="hljs-keyword">Quit</span> sc

UnSubscribe
    <span class="hljs-keyword">Do</span>:<span class="hljs-built_in">$SYSTEM</span>.Event.Defined(resourceName) <span class="hljs-built_in">$SYSTEM</span>.Event.Clear(resourceName), <span class="hljs-built_in">$SYSTEM</span>.Event.Delete(resourceName)
    <span class="hljs-keyword">Kill</span> @node
    <span class="hljs-keyword">Quit</span>
WaitAck
    <span class="hljs-keyword">Set</span> start = <span class="hljs-built_in">$zh</span>, match = <span class="hljs-built_in">$$$NO</span>
    <span class="hljs-keyword">Do</span> {
        <span class="hljs-keyword">Set</span> syncResult = <span class="hljs-built_in">$SYSTEM</span>.Event.WaitMsg(<span class="hljs-string">""</span>, ..#ACKTIMEOUT)
        <span class="hljs-keyword">Set</span> syncStatus = <span class="hljs-built_in">$ListGet</span>(syncResult, <span class="hljs-number">1</span>)
        <span class="hljs-keyword">If</span> syncStatus &lt; <span class="hljs-number">1</span> <span class="hljs-keyword">Do</span> UnSubscribe <span class="hljs-keyword">Quit</span>
        <span class="hljs-keyword">Set</span> msg = {}.<span class="hljs-built_in">%FromJSON</span>(<span class="hljs-built_in">$ListGet</span>(syncResult, <span class="hljs-number">2</span>))
        <span class="hljs-keyword">Set</span> match = msg.MessageID = NotifyObject.MessageID <span class="hljs-comment">; Ok this is the expected ack</span>
        <span class="hljs-keyword">Quit</span>:match
    } <span class="hljs-keyword">While</span> (start + ..#ACKTIMEOUT &gt; <span class="hljs-built_in">$zh</span>)

    <span class="hljs-keyword">Do</span>:'match UnSubscribe <span class="hljs-comment">; no ACK received -&gt; force Unsubscribe this subscriber</span>
    <span class="hljs-keyword">Quit</span>
}

<span class="hljs-keyword">ClassMethod</span> GenEventObject(Event <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span>) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>
{
    <span class="hljs-keyword">Quit</span> {
        <span class="hljs-string">"Event"</span>:(Event),
        <span class="hljs-string">"EventType"</span>:(<span class="hljs-built_in">$Piece</span>(Event,<span class="hljs-string">":"</span>,<span class="hljs-number">1</span>)),
        <span class="hljs-string">"EventName"</span>:(<span class="hljs-built_in">$Piece</span>(Event,<span class="hljs-string">":"</span>,<span class="hljs-number">2</span>)),
        <span class="hljs-string">"PIDSource"</span>:(<span class="hljs-built_in">$JOB</span>),
        <span class="hljs-string">"Timestamp"</span>:(<span class="hljs-built_in">$ZDateTime</span>(<span class="hljs-built_in">$Horolog</span>,<span class="hljs-number">3</span>,<span class="hljs-number">1</span>)),
        <span class="hljs-string">"MessageID"</span>:(<span class="hljs-built_in">$Increment</span>(<span class="hljs-symbol">^dc</span>.ipcutils.msg)) 
    }
}

<span class="hljs-keyword">ClassMethod</span> HashContext(Context <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%String</span> [ CodeMode = expression, Internal, Private ]
{
<span class="hljs-built_in">$ZCRC</span>(<span class="hljs-built_in">$Select</span>(<span class="hljs-built_in">$IsObject</span>(Context):Context.<span class="hljs-built_in">%ToJSON</span>(),<span class="hljs-number">1</span>:Context),<span class="hljs-number">7</span>)
}

<span class="hljs-keyword">ClassMethod</span> ShowSubscribed()
{
    <span class="hljs-keyword">Set</span> node = <span class="hljs-built_in">$Name</span>(<span class="hljs-built_in">$$$Subscribed</span>)
    <span class="hljs-keyword">For</span>  {
        <span class="hljs-keyword">Set</span> node = <span class="hljs-built_in">$Query</span>(@node,<span class="hljs-number">1</span>,value)
        <span class="hljs-keyword">Quit</span>:node=<span class="hljs-string">""</span>
        <span class="hljs-keyword">Write</span> !,<span class="hljs-string">" * Event: "</span>, <span class="hljs-built_in">$QSubscript</span>(node,<span class="hljs-number">1</span>), <span class="hljs-string">"  ClassName: "</span>, <span class="hljs-built_in">$QSubscript</span>(node,<span class="hljs-number">2</span>)
        <span class="hljs-keyword">Write</span> !,<span class="hljs-string">"   Date time: "</span>,<span class="hljs-built_in">$Lg</span>(value,<span class="hljs-number">3</span>)
        <span class="hljs-keyword">Write</span> !,<span class="hljs-string">"   PID: "</span>, <span class="hljs-built_in">$Lg</span>(value,<span class="hljs-number">4</span>)
        <span class="hljs-keyword">Write</span> !,<span class="hljs-string">"   Context: "</span>,<span class="hljs-built_in">$Lg</span>(value,<span class="hljs-number">5</span>)
        <span class="hljs-keyword">If</span> <span class="hljs-built_in">$ListGet</span>(value,<span class="hljs-number">6</span>)=<span class="hljs-number">1</span> <span class="hljs-keyword">Write</span> !,<span class="hljs-string">"   ResourceName: "</span>,<span class="hljs-built_in">$QSubscript</span>(node,<span class="hljs-number">3</span>)
    }
    <span class="hljs-keyword">Quit</span>
}

<span class="hljs-keyword">ClassMethod</span> <span class="hljs-keyword">Kill</span>() [ Internal ]
{
    <span class="hljs-keyword">Kill</span> <span class="hljs-built_in">$$$Subscribed</span>
}

}

</code></pre>
<p>With the "Manager" in place, we can now develop a concrete listener:</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-comment">/// Basic Listener for demo purpose&lt;br/&gt;</span>
<span class="hljs-comment">/// Open a terminal: &lt;br/&gt;</span>
<span class="hljs-comment">/// Set listener = ##class(dc.ipcutils.BasicListener).%New()&lt;br/&gt;</span>
<span class="hljs-comment">/// Do listener.Listen()&lt;br/&gt;</span>
<span class="hljs-comment">/// or in one line : Do ##class(dc.ipcutils.BasicListener).%New().Listen()&lt;br/&gt;</span>
<span class="hljs-comment">/// Type ctrl+c to stop.&lt;br/&gt;</span>
<span class="hljs-comment">/// Open anoter terminal:&lt;br/&gt;</span>
<span class="hljs-comment">/// Do ##class(dc.ipcutils.Manager).Notify("Demo:OnTestString","This is string notification")&lt;br/&gt;</span>
<span class="hljs-comment">/// Do ##class(dc.ipcutils.Manager).Notify("Demo","This is a demo notification")&lt;br/&gt;</span>
<span class="hljs-comment">/// Do ##class(dc.ipcutils.Manager).Notify("Demo:OnTestObject",{"object":"demo"})&lt;br/&gt;</span>
<span class="hljs-keyword">Class</span> dc.ipcutils.BasicListener <span class="hljs-keyword">Extends</span> dc.ipcutils.ListenerAbstract
{

<span class="hljs-keyword">Parameter</span> EVENTTYPE = <span class="hljs-string">"Demo"</span><span class="hljs-comment">;</span>
<span class="hljs-keyword">Parameter</span> VERBOSE = <span class="hljs-number">1</span><span class="hljs-comment">;</span>
Method Listen() <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    <span class="hljs-keyword">Set</span> sc = <span class="hljs-built_in">$$$OK</span>
    <span class="hljs-built_in">$$$QuitOnError</span>(<span class="hljs-built_in">..OnStartListen</span>())
    <span class="hljs-keyword">Try</span> {
        <span class="hljs-keyword">Write</span>:<span class="hljs-built_in">..Verbose</span> !,<span class="hljs-built_in">$zdt</span>(<span class="hljs-built_in">$h</span>,<span class="hljs-number">3</span>,<span class="hljs-number">1</span>),<span class="hljs-string">" + Type &lt; ctrl+c &gt; to stop listening."</span>
        <span class="hljs-keyword">For</span>  <span class="hljs-keyword">If</span> <span class="hljs-built_in">..Wait</span>() = -<span class="hljs-number">1</span> <span class="hljs-built_in">$$$ThrowStatus</span>(<span class="hljs-built_in">$$$ERROR</span>(<span class="hljs-built_in">$$$GeneralError</span>,<span class="hljs-built_in">$$$FormatText</span>(<span class="hljs-string">"Resource %1 deleted."</span>,<span class="hljs-built_in">..ResourceName</span>)))
    } <span class="hljs-keyword">Catch</span> Ex {
        <span class="hljs-keyword">If</span> Ex.Name '[ <span class="hljs-string">"&lt;INTERRUPT&gt;"</span> <span class="hljs-keyword">Set</span> sc = Ex.AsStatus()
        <span class="hljs-keyword">If</span> <span class="hljs-built_in">..Verbose</span>, <span class="hljs-built_in">$$$ISERR</span>(sc) <span class="hljs-keyword">Do</span> <span class="hljs-built_in">$SYSTEM</span>.Status.DisplayError(sc)
    }
    <span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$ADDSC</span>(sc,<span class="hljs-built_in">..OnStopListen</span>())
}

Method Update(
	Event <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>,
	Data <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>,
	Context <span class="hljs-keyword">As</span> <span class="hljs-built_in">%DynamicObject</span>) <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    <span class="hljs-keyword">Set</span> dt = <span class="hljs-built_in">$ZDateTime</span>(<span class="hljs-built_in">$Horolog</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>)
    <span class="hljs-keyword">Write</span>:<span class="hljs-built_in">..Verbose</span> !,dt,<span class="hljs-string">" + Update received!"</span>
    <span class="hljs-keyword">Write</span> !,dt, <span class="hljs-string">" = Event : "</span>, !
    <span class="hljs-keyword">Do</span> <span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%JSON.Formatter</span>).<span class="hljs-built_in">%New</span>().Format(Event)
    <span class="hljs-keyword">Write</span> !,dt, <span class="hljs-string">" = Context : "</span>, !
    <span class="hljs-keyword">Do</span> <span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%JSON.Formatter</span>).<span class="hljs-built_in">%New</span>().Format(Context)
    <span class="hljs-keyword">Write</span> !,dt, <span class="hljs-string">" = Data : "</span>, !
    <span class="hljs-keyword">Do</span> <span class="hljs-keyword">##class</span>(<span class="hljs-built_in">%JSON.Formatter</span>).<span class="hljs-built_in">%New</span>().Format(Data)
    <span class="hljs-keyword">Quit</span> <span class="hljs-built_in">$$$OK</span>
}

<span class="hljs-keyword">ClassMethod</span> Test() <span class="hljs-keyword">As</span> <span class="hljs-built_in">%Status</span>
{
    <span class="hljs-keyword">Quit</span> ..<span class="hljs-built_in">%New</span>().Listen()
}

}

</code></pre>
<p>Everything is finally ready for testing. Open a terminal (or several) with an instance of "dc.ipcutils.BasicListener":</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Do</span> <span class="hljs-keyword">##class</span>(dc.ipcutils.BasicListener).Test()</code></pre>
<p>Another instance is also required to notify "Demo" events:</p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos"><span class="hljs-keyword">Do</span> <span class="hljs-keyword">##class</span>(dc.ipcutils.Manager).Notify(<span class="hljs-string">"Demo:OnTest"</span>,{<span class="hljs-string">"Message"</span>:<span class="hljs-string">"My FirstTest"</span>}.<span class="hljs-built_in">%ToJSON</span>())</code></pre>
<p><span style="font-size:11pt; font-variant:normal; white-space:pre-wrap"><span style="font-family:Arial,sans-serif"><span style="color:#000000"><span style="font-weight:400"><span style="font-style:normal"><span style="text-decoration:none">It will result in the following output in the first terminal</span></span></span></span></span></span></p>
<pre class="codeblock-container" idlang="0" lang="ObjectScript" tabsize="4"><code class="language-cls hljs cos">IRISAPP&gt;<span class="hljs-keyword">d</span> <span class="hljs-keyword">##class</span>(dc.ipcutils.BasicListener).Test()

<span class="hljs-number">2023</span>-<span class="hljs-number">10</span>-<span class="hljs-number">17</span> <span class="hljs-number">19</span>:<span class="hljs-number">20</span>:<span class="hljs-number">34</span> + Listening Demo with resourcename MjAxMjIzMzE5NzkwOTg1 started.
<span class="hljs-number">2023</span>-<span class="hljs-number">10</span>-<span class="hljs-number">17</span> <span class="hljs-number">19</span>:<span class="hljs-number">20</span>:<span class="hljs-number">34</span> + Type &lt;ctrl+c&gt; to stop listening.
<span class="hljs-number">2023</span>-<span class="hljs-number">10</span>-<span class="hljs-number">17</span> <span class="hljs-number">19</span>:<span class="hljs-number">20</span>:<span class="hljs-number">44</span> + Update received!
<span class="hljs-number">2023</span>-<span class="hljs-number">10</span>-<span class="hljs-number">17</span> <span class="hljs-number">19</span>:<span class="hljs-number">20</span>:<span class="hljs-number">44</span> = Event: 
{
  <span class="hljs-string">"Event"</span>:<span class="hljs-string">"Demo:OnTestObject"</span>,
  <span class="hljs-string">"EventType"</span>:<span class="hljs-string">"Demo"</span>,
  <span class="hljs-string">"EventName"</span>:<span class="hljs-string">"OnTestObject"</span>,
  <span class="hljs-string">"PIDSource"</span>:<span class="hljs-string">"20165"</span>,
  <span class="hljs-string">"Timestamp"</span>:<span class="hljs-string">"2023-10-17 19:20:44"</span>,
  <span class="hljs-string">"MessageID"</span>:<span class="hljs-number">2171</span>
}
<span class="hljs-number">2023</span>-<span class="hljs-number">10</span>-<span class="hljs-number">17</span> <span class="hljs-number">19</span>:<span class="hljs-number">20</span>:<span class="hljs-number">44</span> = Context: 
{
}
<span class="hljs-number">2023</span>-<span class="hljs-number">10</span>-<span class="hljs-number">17</span> <span class="hljs-number">19</span>:<span class="hljs-number">20</span>:<span class="hljs-number">44</span> = Data: 
{
  <span class="hljs-string">"object"</span>:<span class="hljs-string">"demo-1"</span>
}

</code></pre>
<p>You ultimately have a functional and relatively simple example of setting up. Just create a class that inherits from "dc.ipcutils.ListenerAbstract"&nbsp;and adapt it to your needs. Although it is not the Observer Pattern, this solution allows us to reach our goals.</p>
<p>See you soon!</p>