Omar Laurino added text in the architecture section  about 10 years ago

Commit id: c63710225f235dcfdaf6ebdffab155e8ac312697

deletions | additions      

       

\section{A loosely coupled, event-driven, extensible architecture}  \label{sec:architecture}  \section{A In order to minimize the risk deriving from such requirements, we backed Iris with a  loosely coupled, event-driven, coupled architecture through a design pattern called Inversion of Control [REFERENCE].  But it's not just a matter of risk management: this design pattern also supports the implementation of "liquid requirements", i.e. a finite set of predetermined requirements plus an undefinite set of custom requirements to be implemented by users in some simple cases or by third party developers plug-ins for more advanced functionality.  The architecture supporting the implementation of such requirements has different components that can be classified in terms of the Model-View-Controller (MVC) design pattern:  \begin{itemize}  \item[SEDLib] a basic I/O library provides the most basic abstraction of the Model component of MVC. Unsurprisingly, SEDLib can do so by implementing a Data Model specification defined by the IVOA. Such specification defines both the logical breakdown of spectral datasets, and the serialization in some standard file formats. So, on one end, SEDlib can perform the basic read/write operations on spectrophotometric files, while on the other it provides the data structures that client components can use and exchange.  \item[SEDManager] The MVC Controller role is played in Iris by the SEDManager, which is itself defined as an Interface. The manager works as a data storage for SEDLib instances that the different Iris components can share.  \item[Components] The actual Iris functionality is implemented by the Iris Components. They can be seen as the Views in the MVC pattern (or, more generally, they can provide any number of Views), since they present to the user the data stored in the Controller, query the Controller itself, and act upon the Models, i.e. the SED objects provided by SEDLib.  \item[Events] Views can be notified of changes in the Models (possibly triggered by other Views via the Controller) by Events, if they implement the relative Listener interface and by registering to the Events Queue. Such Queue effectively decouples all of the Components. Events usually have a payload with more information about their content, and a pointer to the Model (or Models) involved. For convenience, Events are usually fired by the SEDManager itself, but in principle any class in Iris can trigger them.  \end{itemize}  In summary, Components (Views) can be completely disentangled from each other and interact indirectly through the sole common interface represented by the SEDManager (Controller), which in turn stores the SED objects (Model). Dynamic changes in the system are notified to all interested agents (Listeners) via specific Events.  Components are thus agents that cohoperate by attaching themselves to a common \emph{bus} where the SEDManager provides the memory, and Events guarantee the flow of information.  \subsection{Inversion of Control}  We achieve loose coupling by an extensive use of Java Interfaces: components, events, and event listeners, for example, are all defined by interfaces whose implementation can, to some extent, be freely interchangeable.  Moreover, Inversion of Control is employed to decouple the implementation of components from the run time context: methods in the Interface are callback, and some of these callbacks get Interface-typed arguments which provide them context instances during the application execution. This is also sometimes referred to as Dependency Injection.  Consider, for example, Iris Components: they are the main providers of Iris functionality, and they can correspond to buttons and menu items on the Iris desktop, loggers, data handlers, etc. They must implement the IrisComponent interface, which is listed in Listing \ref{lst:component}.  At startup the Iris application reads the list of Components to be initiated, and calls their init call-back, which is in turn passed useful information like the SEDManager, or hooks to the application environment (more information is provided in the following sections).  The advantages of this architecture are both functional and non functional: it helped our heterogeneous developing team to work in a loosely coupled way, reducing the overall project risk, but it also provides the  extensible architecture} framework we were seeking in the first place. As a matter of fact, Plug-ins that can be loaded at run time (see section \ref{plugins}) implement the same interfaces that the built-in components do (see section \ref{builtin}), and they are instantiated exactly the same way. The only difference is in the timing: built-in Components get instantiated when the application itself is intialized, while plug-in can be instantiated (and discarded) at any time during the application execution.