blob: f575710d225e8b82faa7202e21daadf21cbf51c2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2018 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* SAP AG - initial API and implementation
******************************************************************************/
package org.eclipse.ocl.examples.eventmanager.framework;
/**
* This package contains the core of the EventFramework implementation. It mainly consists of three parts:
* <ul>
* <li>The <code>SessionEventManager</code> (which implements both interfaces the EventFramework provides to clients
* and to the repository core)</li>
* <li>The <code>RegistrationManager</code> (which manages the <code>Registrations</code> using the
* <code>EventFilterTables</code>)</li>
* <li>The <code>EventFilterTables</code> (which store the <code>Registrations</code> and provide all
* <code>Registrations</code> that might be interested in a notification)</li>
* </ul>
* <br>
* <br>
* <b>A brief overview of the core mechanisms:</b><br>
* <br>
* <b>Registering new Listeners:</b><br>
* When a new listener is registered using the appropriate method on the <code>EventManager</code> interface, the
* SessionEventManager assigns the matching <code>Notifier</code> and delegates the registration to its
* <code>RegistrationManager</code>. The <code>Notifier</code> encapsulates the knowledge how to notify the
* listeners. <code>CommitListeners</code> for example do not want to get notified directly, but when the command was
* committed.<br>
* The <code>RegistrationManager</code> does the main work: First, it transforms the passed tree of
* <code>EventFilters</code> into the disjunctive normal form. This means, that the resulting tree has a depth of 2
* and consists of an <code>ORFilter</code> at the root which connects multiple <code>ANDFilters</code> which
* connect the atomic leaves (the real filters) of the tree. This is needed due to the fact, that the algorithm that
* computes all affected registrations for an event is only able to implement AND conjunctions, but no logical OR. The
* logical OR is emulated by a split-up into one <code>Registration</code> per operand of the root filter. Each atomic
* filter then is registered in its associated <code>EventFitlerTable</code> (there is a 1 to 1 mapping of the filter
* type to the type of the FilterTable). Afterwards, all <code>Registrations</code> that were created during one
* registration call are pooled in a <code>RegistrationSet</code> in order to be able to distinguish between a
* listener that registered once using a logical OR and a listener that registered twice without an OR.<br>
* The <code>EventFilterTable</code> connects the filter's criterion with the associated <code>Registrations</code>.
* There are two sets of Registrations associated with the filter criterion: The RegistrationSet (all registrations
* registered for the criterion) and the NegatedRegistrationSet (all registrations registered for "NOT the filter
* criterion"). <br>
* <br>
* <b>Computing the Set of affected registrations in the context of an event:</b><br>
* The <code>SessionEventManager</code> delegates the computation to the RegistrationManager. Afterwards it orders the
* associated <code>Notifier</code> to notify its listener.<br>
* The RegistrationManager asks all affected <code>EventFilterTables</code> for their contribution. (There is a 1 to n
* mapping of the event types to the types of the filter tables.) All the mappings of the <code>EventFilterTables</code>
* are realized in the init() method of a subclass of <code>RegistrationManager</code>, called
* <code>SessionRegistrationManager</code>. Each <code>EventFilterTable</code> can contibute 2 sets of
* Registrations for an event: The <code>Registrations</code> for an event and the negated Registrations for an event
* (these sets do not only consist of RegistrationSet and NegatedRegistrationSet). The <code>RegistrationManager</code>
* then merges all "<code>Registrations</code> for the event" into one set and deletes all "negated
* <code>Registrations</code> for the event". Then, all <code>Registrations</code> that are contained in the same
* <code>RegistrationSet</code> are pooled. As each <code>Registration</code> knows its associated
* <code>Listener</code>, the <code>RegistrationManager</code> can easily return the set of affected listeners.<br>
* Each <code>EventFilterTable</code> knows which information to extract from the passed event (this is the
* information that can be compared with the filter criterion). The "<code>Registrations</code> for an event" consist of
* the RegistrationSet of the matching filter criterion plus the NegatedRegistrationSets of all other registered criterions.
* The "negated <code>Registrations</code> for an event" consist of the NegatedRegistrationSet that is associated with the
* matching filter criterion plus all RegistrationSets of all other filter criterions. Due to performance reasons, this logic
* is encapsulated in the <code>RegistrationIterator</code>, so that no sets have to be copied.
*/