J. Templ, Nov. 8th, 2004
The basic structure of the application server
is nowadys known as an IoC container or an IoC framework,
where IoC stands for 'Inversion of Control'.
Popular projects which develop around this notion are Apache Avalon/Turbine,
PicoContainer/NanoContainer, Spring, or OSGI, to name just a few.
Often, such a system is also called a 'lightweight' container as opposed to an Enterprise
Java Beans (EJB) container, which is usually considered to be a heavyweight container
both in terms of conceptual complexity and in terms of runtime resources needed.
KITE and many if not all of the mentioned approaches are essentially a non-standard
alternative to EJB.
The term IoC has been criticized by Martin Fowler and the alternative term 'Dependency Injection'
has been coined by Fowler. We agree with Fowler that the term IoC should be avoided because
inversion of control is a property of every framework and thus fails to characterize a
particular kind of framework. We are not sure, however, if dependency injection
is a much better term as it focuses around the ways of specifying dependencies between
services, which is only one aspect to be solved. In our oppinion, the pattern being
employed is nothing else but that of the 25 years old module loader or the
10 years old class loader with imports specifying the relationships
and with the important property that a module or class is being loaded only once into
a container, thus modules and classes serve as a static decomposition of an application.
This can be adapted easily to a service container dealing with
service instances rather than loading modules or classes.
Interface versus Implementation
A major difference between the newer projects and KITE is that KITE is both
a specification AND an implementation, whereas Avalon or PicoContainer, for example, are
a domain independent set of interfaces to be implemented by other
more domain specific projects. Seen as a specification, the
kite.service roughly corresponds with Avalon,
for example. KITE is not intended to be a general purpose container
for an unknown target domain, but a container for the needs of an application
server to be used in the context of E-business applications. Therefore it can focus
on the needs of these usage scenarios, drop any exotic or speculative features,
and provide exactly the required support in the base architecture.
The resulting architecture is not explicitly targeted at E-Business applications,
but designed such that the kind of services, that are required can be
provided and combined easily. There is no database service in the KITE architecture,
for example, but the architecture allows one to introduce a database service
and even higher level services on top of a database service.
Since KITE provides a number of non-trivial standard services and service containers,
it is proven that the architecture is well suited at least for the intended target domain.
In particular KITE service containers provide features such as
transparent local or remote usage,
remote execution with compression and/or encryption and/or tunneling via http,
hot deployment of applications, clustering of servers,
localization of services, a concept for exeption handling, and a concept
for flexible and convenient configuration of applications.
The available standard services include logging, advanced database access, and OR-mapping.
The life cycle model of KITE is rather simple compared with other
approaches but more advanced in at least one respect: exception handling.
KITE provides a conceptual framework and life cycle support for resetting services
contained in a service container after an exception has been caught.
The basic idea is that exceptions should only be used for handling 'unexpected'
situations, not as an alternative for function results. If an exception is thrown, there
is no way except informing the user (i.e. the top level program that invoked a service)
of the exception. Hiding the exception by catching it somewhere at a deeper level is
counter productive and impossible in the general case, because the service cannot
know about the state of other services that might need to be reset.
An example is a user action that invokes a sequence of different
services with a database transaction being involved.
Now if one of the non-DB-services throws an exception, the database transaction
must be rolled back, but this cannot be known to the faulty service. Therefore KITE
requests that exceptions are propagated to the top level and are thus handled at a central
place. The top level exception handler informs the user and
resets the service container, which in turn resets all
services of the container. In our experience, it is a widespread
misunderstanding that local exception handlers
together with exceptions declared explicitly in a method's signature improve the
quality of all programs. For frameworks the opposite is true. A framework cannot
anticipate the implementation of its plugins and therefore has to cope with all kinds of
exceptions. In other words, a framework has to expect the unexpected.
The omission of such a concept for exception handling in more recent
approaches is a severe problem for reliable and systematic exception
handling in application development.
It might appear as a trivial addendum to many application developers that
most services need to be configured in order to work properly.
A database service, for example, needs to know the parameters for opening
a database connection. In practice it turns out that configuration is
a time consuming and error prone task that deserves some support.
Most approaches use XML and document type definitions (DTD)
for configuration tasks. KITE introduced the notion of
profiles (property files) as a hierachical Java property file and property type
definitions (PTD) for specifying the names and types of properties.
In addition, KITE supports inheritance of property types, which is not supported
by DTD and poorly supported by other schema definition languages.
A KITE property type definition may be defined as an extension of another
property type definition, which introduces polymorphism and compatibility between
the base type and the extensions. Thus, a KITE application profile can for example
be declared as a list of services, where every service has some basic properties and
according to the particular service class it can introduce additional properties.
A generic profile editor provides a GUI for defining properties and abstracts from
the underlying implementation. We found property inheritance of paramount importance
for organizing the configuration of applications. Surprisingly, it seems that this is not a topic
for any of the alternative general purpose approaches.
A short look into alternative approaches unveils that all of them are
considerably more complex than KITE. OSGI (Release 3), for example is specified
in as much as 600 pages (including various standard services).
In general, this complexity may be attributed to the goal of
domain independency, but it is not really clear if this helps the
application developer to get his or her work done. It is also much more complex to implement
the specifications because a large number of sophisticated interfaces
with subtle semantics must be mastered by a conforming runtime system.
We believe that KITE is the only system that has been reduced to
the absolute minimum number of orthogonal concepts, while still being a powerful open
platform for a variety of environments and services.
A promising approach therefore seems to be to take the KITE architecture as a baseline
and see how far one can go with it and what, if any, the principal limitations are.
It would be interesting to compare the KITE architecture and
implementation with Avalon and Turbine, for example and to see if the
standard KITE services can be implemented without any loss of functionality
and without introducing any non-standard extensions into Avalon.
It might also be interesting to compare
KITE with the 'Spring' framework developed by Rod Johnson and Jürgen Höller
and to learn more about Spring in general.