Title:   GAP Component Architecture
Status:  Obsolete
Created: 2006-03-28

The component architecture is based upon a similar architecture in Zope3. In
uses several modules from zope3 in fact as it's foundation.  In GAP,  applications
consist of components known as services and utilities.  

  Services
    As in zope3,  services are the mission critical components of an 
    application.  If a service will not load then the application is 
    non-functional.  An example of a service would be the datasource 
    manager service in an application that processes information in
    the database.
    
  Utilities
    Utilities are less critical components of an application.  A failure 
    to load a utility doesn't result in application failure.  An example
    of an utility would be a component that adds a google style search
    bar to your applications toolbar.
    
It's worth noting that almost any component might be a service in one
application and a utility in another.  For example, the datasource
manager component would be application critical in an application that 
manipulated an database.  However it might be a utility in a call center
monitoring application that attempted to store logs in a database but 
could continue to display information if the database connection was
unavailable.

More on Components 
  Component Interfaces
    Components are written to an interface and can only communicate with
    each other across that interface.  Once a component interface API
    is stablized that interface will remain consistant.  While slanted 
    toward java application the  "Life-cycle of an API" and 
    "Preservation of Investments" sections of the document at 
    http://openide.netbeans.org/tutorial/api-design.html are worth taking
    into consideration 
  
  Component Assembly
    Components are basically the building blocks of an application.  An
    application developer will take existing GAP components, add a few 
    custom components and plug them together to form a new application.
    This assembly can either be done in python code for simple applications
    or it can be done via an application specific manifest file.
    
    By providing for a file based assembly of components we make it 
    simple to take an existing application such as GNUe Designer, remove
    components we don't need, and tack on new components to the remaining 
    pieces.
  
  Component Registry
    The component registry is responsible for maintaining the current 
    components loaded into an application.  It handles the loading of
    components, processes requests for handles to components, reloads
    components if required.  It will also probably deal with dependency
    mapping so that components get loaded in the proper order.
    
    Since all components will interface with the component registry, 
    it's interface will be kept small and simple.  Components are 
    registered by both the Interface they provide and by a name. 
    

Advantages of the Component Architecture (some taken from IRC logs)

  Extensiblity
    New components can be added to applications at the end user site.
    Say I wanted to write a call queue monitor for my call center at 
    work to replace the full screen one we currently use.  I want this
    monitor to add a button to my GNUe Forms toolbar that shows current
    number of calls holding.  If the button is pressed I want it to launch
    my full screen monitor.  By creating a component that registers this
    button on my Forms toolbar I've extended forms without needing to 
    know all the Forms internals.  I only needed to learn how to load and
    register my component with GAP and the API to add a button to the 
    toolbar.  Later if I were to port my primary sales application to 
    the GAP platform then I could reuse that same component in that 
    app as well.
    
  Maintainability
    One issue we've faced in the GNUe applications is broken encapsulation.
    Often times we hard link through numerous classes to get to the instance
    we need.  An example from GNUe Forms reads 
    
    self._dataSourceLink._connection.rollback ()
    
    With components we'd do something along the lines of 
    
      queryComponent(IConnectionManager) 
      or
      queryComponentPool(IConnectionManager)
       
    to get a handle a connection manager that was registered for the 
    application.  As a result code no longer needs to care about the
    location of an instance in the application heirarchy.  It only
    needs to know the Interface it requires and the API that interface
    provides.
    
    Component APIs will also be kept as clean and small as possible
    in order to maximize flexibility in the future.  The less API we
    expose the easier it is to replace that component with a new 
    implementation and not break existing code.
     
  Flexibility
    Component based applications also provide unique oprotunities in 
    customization of applications.  It is possible to replace or extend
    existing services by replacing that service in an application.  While 
    this would be handy in testing new replacement components another 
    possibility exists.
    
    Since components ask for other components by Interface it is possible
    to wrapper existing components inside another component that modifies
    the behaviour of the existing component.  For the pattern crazed amongst 
    us I believe you'd call this a decorator pattern.  An example
    
    Example: Connection tracking
    
    Lets say FooCorp wants to log all login attempts on their system to a line 
    printer.  
    
    They could ask us to add the functionality to out connection manager.
    However this is unlikely to be possible for every request and would
    result in a fairly bloated connection manager code base and API over 
    time.
    
    They could modify the existing connection manager login method to send 
    the desired output to the line printer.  But they'd have to then track 
    updates to our base code and remerge their changes after each upgrade.
    
    They could subclass our login manager, add a call to the login method
    to send the desired output to the line printer, then call the existing
    method in the superclass.  They would then need tofind all references 
    to the original class and replace them.  Again creating update maintenance
    after each new release.
    
    But with the component system they could still subclass our connection manager, 
    or write their own to the same API.  They would then adjust the application
    manifest to load their connection manager instead of our own.  When loaded, 
    their custom connetion manager still would register itself as proving the IConnectionManager
    interface.  GAP appliations are not coded to a specific connection manager
    class located in a specific module.  Instead they query the component registry
    for the component that provides an IConnectinManager interface, like this.
    
      queryComponent(IConnectionManager) 
      
    So existing applicatoins will not notice the change.  If they've subclassed 
    our connection manager then they would get any security updates without
    requiring any appication changes.  It would even be possible to provide 
    a system wide override file for these components that would allow their 
    on site replacements of components to stay in effect between upgrades
    to applications manifest files.
