back

Short feature dash


0. Preface

0.1 Problem space

In JAVA(c) applications servers like JBoss, WebSphere and so on enable application hosting in a single process.
Each application can provide interfaces and therefore solve seperated concernes of the problem solution isolated. But apart of this each
hosted application can use other applications/components via their provided interfaces in a middleware guided manner.

Otherwise Microsoft(c) defines application servers in a complete other way:

In the Micorosoft (and therefore .net) world the operation system is the application server. This leads to the possibility
that each application can be hosted as windows services - and each one in a different process. --> Each inter-component call
will be realized as a process boundary crossing call.
(We don't need to think about performance drawbacks...)

The project containerOne addresses the lack of an JAVA(c)-like application server in the .net world.

0.2 Definitions

0.2.1 AppServers and the OSGi

As written before - application servers provide a plattform for various applications to be hosted in a single process. Additionally the
application server acts like a middleware which provides unified mechanisms in deployment, registration and inter component calls.

JAVA(c) application servers follow the OSGi standard, which means (in simple words):
  • Elements (e.g. interfaces) of the application must be registered and identified with a unique name
  • Those elements must be start- and stopable
  • The OSGi platfrom needs a remote administration possibility

That's all.

Okay, using a Microsoft operation system (like server 2008) as an application server means:
  • The application will be hosted as a windows service - and this one has a unified name (!)
  • Each service can be started and stopped (!)
  • The service control manager of the windows server can be used remotely (!)
And this fulfills the core OSGi prerequesites... But this enables only a remote OSGi platform. And this is the problem.

Taking all the possible -ilities (like flexibility, scalability etc.) there are only 2 killing arguments:
  1. Stability and
  2. Performance

An application which contains various distributed parts makes a lot of remote calls during runtime => lack of performance.

Therefore my appreciation - Avoid remote (inter-process) calls wherever possible!

This is one of the main points I started this project and I reference the document of Clément Escoffier, Didier Donsez and Richard S. Hall

0.2.2 Component oriented architecture !!!

I'm a big fan of isolated components, where each one concentrates on a dedicated part of the solution.
And in the end all components reside in the process of the application server and interact freely with each other.

A component oriented architecture does not mean that an application can not be designed as a layerd archicture. The layers
are top most view of the architecture and the components within those layers are more fine grained parts (cf. MVC Pattern; The view
part is related to the UI layer and the controller to the business layer).

There are some things that describe a software component:
  • A unique name and a description,
  • a couple of provided interfaces and
  • a couple of needed interfaces from other components.

Therefore each component needs to know the provided interfaces of the other existing components.
If now a component needs other components to fulfill its own work it declares this dependency in its description (simply by placing the
target component's name).

In the end all related components declare a graph of dependencies, where each component is a vertix and the dependency is a unidirectional edge.

Say it with pictures...

Let's take a typical two-tier, three-layer and library architecture. It's clear that each layer calls sublayers from top to bottom and not vice versa.


A more fine grained design, containing components where each one resides in a layer. The calling rules are the same: Top to bottom...


Finally we have a couple of components and their dependencies and can focus now in realizing them.

0.3 Solution space

Now let's get busy - and let me introduce you the road to the solution.

My goal is
  • to enable a component oriented architecture
  • to realize isolated software development

And this with the help of some famous and mighty open source frameworks:
  • Springframework.net - for enabling IoC containers (each component will be a spring container)
  • Quickgraph - for detecting cyclomatic dependencies
  • Castle's Dynamic proxy - for decoupling real implementations from required interfaces

The plan is now to enable an environment for component creation. Each component gets during runtime the
real implementation of needed interfaces from dependent components from the app server's infrastructure.

The best - I start (very unconvenient) from inside out. And each step ends with a list of needed things for realization - and
the next step delivers a way to satisfy this need...

1. Architecture

The best way to describe the architecture is a sample - shown in the following picture (contained in the source).


1.1. The root component C

It can be seen that the component C has no further dependencies - and therefore we start with this one.

Okay, let's define that component C's design is the following:



Now we use spring as wire-up tool to define the configuration.

<objects xmlns="http://www.springframework.net">

  <object id="DoStuff" type="ComponentC.DoStuff, ComponentC"/>

</objects>


This looks very easy until now. But now we have some issues:
  1. As defined earlier - we need to publish the name of the component
  2. The component needs to register itself and the only interface IDoStuff
  3. We need to interact in the init, start and stop phase of the component
  4. Finally the application server needs to find and to start the component

1.1.1. Component name and description

The infrastructure of the application server delivers a class ComponentInformation which will also be defined via spring.

<objects xmlns="http://www.springframework.net">

  <object id="ComponentInformation" type="Harkon.AppServer.cOne.Service.ComponentInformation, cOne">
    <constructor-arg index="0" value="ComponentC"/>
  </object>
  
  <object id="DoStuff" type="ComponentC.DoStuff, ComponentC">
  </object>

</objects>



The component information holds primarily the name of the component. And during runtime it will record all exposed services (interfaces).
Additionally it holds the information if the component shall be autostarted or not and all dependencies.

To enable service (interface) registration within its component container the exposed interface must be decorated as a service name. And this - of course - will be
done via spring:

<objects xmlns="http://www.springframework.net">

  <object id="ComponentInformation" type="Harkon.AppServer.cOne.Service.ComponentInformation, cOne">
    <constructor-arg index="0" value="ComponentC"/>
  </object>
  
  <object id="DoStuff" type="ComponentC.DoStuff, ComponentC">
    <property name="Name" ref="DoStuffName"/>
  </object>

  <object id="DoStuffName" type="Harkon.AppServer.cOne.Service.ServiceName, cOne">
    <constructor-arg index="0" type="string" value="DoStuff"/>
    <constructor-arg index="1" type="Harkon.AppServer.cOne.Service.ComponentInformation, cOne" ref="ComponentInformation"/>
    <constructor-arg index="2" type="string" value="ComponentC.IDoStuff"/>
  </object>

</objects>


1.1.2. Service and component registration

Now that the component is defined, the services declared and named it is time to register this component
at the application server. This is done via the contained service registry and a helper class - the ServiceRegistryPerformer.
To get the registration done the component creates a new instance of the service registry performer via spring.

<objects xmlns="http://www.springframework.net">

  <import resource="spring-component.config"/>

  <object id="ComponentInformation" type="Harkon.AppServer.cOne.Service.ComponentInformation, cOne">
    <constructor-arg index="0" value="ComponentC"/>
  </object>
  
  <object id="DoStuff" type="ComponentC.DoStuff, ComponentC">
    <property name="ServiceRegistry" ref="ServiceRegistryProxyFactory"/>
    <property name="Name" ref="DoStuffName"/>
  </object>

  <object id="DoStuffName" type="Harkon.AppServer.cOne.Service.ServiceName, cOne">
    <constructor-arg index="0" type="string" value="DoStuff"/>
    <constructor-arg index="1" type="Harkon.AppServer.cOne.Service.ComponentInformation, cOne" ref="ComponentInformation"/>
    <constructor-arg index="2" type="string" value="ComponentC.IDoStuff"/>
  </object>

  <object id="ServiceRegistryPerformer" type="Harkon.AppServer.cOne.Deployment.ServiceRegistryPerformer, cOne">
    <property name="ServiceRegistry" ref="ServiceRegistryProxyFactory"/>
    <property name="LocalServices">
      <dictionary key-type="string" value-type="Harkon.AppServer.cOne.Service.IService, cOne">
        <entry key="DoStuff" value-ref="DoStuff"/>
      </dictionary>
    </property>
  </object>

</objects>


The registry performer records all exposed interfaces and registers them in the service registry of the application server.
But the problem is now, that the service registry is a singleton service itself - registered in the infrastructure component of the application server.
How does the new component gets a reference to this unique service? In two steps:
  1. A Castle proxy for the registry will be inserted (and configured via Spring) into the container.
  2. During deploy of the component the infrastructure injects the real implementation of the service registry into the proxy.

As written in spring config file line 3 the spring file imports a given one spring-component.config.

This xml file looks like this:

<objects xmlns="http://www.springframework.net">

  <object id="ServiceLifecycleManager" type="Harkon.AppServer.cOne.Service.ServiceLifecycleManager, cOne">
    <property name="ComponentInformation" ref="ComponentInformation"/>
  </object>
  
  <object id="ServiceRegistryProxy" type="Harkon.AppServer.cOne.Registry.RegistryProxy, cOne">
  </object>

  <object id="ServiceRegistryProxyFactory" type="Harkon.AppServer.cOne.Registry.ServiceRegistryProxyFactory, cOne" factory-method="CreateServiceProxy&lt; Harkon.AppServer.cOne.Registry.IRegistry>">
    <constructor-arg name="interceptor" ref="ServiceRegistryProxy"/>
  </object>
  
</objects>

1.1.3. Service init, start and stop

For this issue we need typical methods (like Init(), Start(), Stop()). Because of being related to a lifecycle of a service those methods are contained in a infrastructure interface ILifecycleAware.
Additionally the infrastructure provides a service interface IService. Each element extending this interface can be recorded in the service registry of the application server.

In the following class diagram the component C will be shown completely with all infrastructure elements:



One of the advantages of an abstract service class is, that the default behavior of the lifecycle methods can be defined centrally. In special cases it is possible to override this behavior - therefore the methods implementations in the abstract class are virtual.

1.1.4. Auto-deployment

Okay, now the last issue: The application server shall deploy the component (and all contained services) at startup.

The JBoss application server solves this by "watching" a dedicated directory. At startup (and during runtime - hot deploy) the server detects deployable elements. And this is nearly the same as the container one application server starts deployable elements:
  • The server detects deployable elements by name which means: It searches in the deploy directory xml files with the name pattern componentName-description.xml
  • This xml file contains the name, the dependencies and the autostart flag of the current component -> this results in the previously described dependency graph
  • Now - for each found component - the deployment manager of the server searches in the deploy directory a spring configuration file called componentName-spring.config
  • This file will be read by the bean factory of the spring.net framework
  • If the autostart flag of the component is set to true the container starts the components services via the init and start methods

And that's it...

The componentName-description.xml file may look like this (for component C):

<?xml version="1.0" encoding="utf-8"?>
<description xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>ComponentC</Name>
  <Autostart>true</Autostart>
</description>

1.2. The component A

Now let's take a look at the component A which depends on the existing and running component C.

The component description xml file:
<?xml version="1.0" encoding="utf-8"?>
<description xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>ComponentA</Name>
  <Autostart>true</Autostart>
  <Dependencies>ComponentC</Dependencies>
</description>


The class diagram:


And the spring config:
<?xml version="1.0" encoding="UTF-8"?>
<objects xmlns="http://www.springframework.net">

  <import resource="spring-component.config"/>

  <object id="ComponentInformation" type="Harkon.AppServer.cOne.Service.ComponentInformation, cOne">
    <constructor-arg index="0" value="ComponentA"/>
  </object>

  <object id="WillUse" type="ComponentA.WillUse, ComponentA">
    <property name="Others" ref="DoStuffProxyFactory"/>
    <property name="ServiceRegistry" ref="ServiceRegistryProxyFactory"/>
    <property name="Name" ref="WillUseName"/>
  </object>

  <object id="WillUseName" type="Harkon.AppServer.cOne.Service.ServiceName, cOne">
    <constructor-arg index="0" type="string" value="WillUse"/>
    <constructor-arg index="1" type="Harkon.AppServer.cOne.Service.ComponentInformation, cOne" ref="ComponentInformation"/>
    <constructor-arg index="2" type="string" value="ComponentA.IWillUse"/>
  </object>

  <object id="ServiceRegistryPerformer" type="Harkon.AppServer.cOne.Deployment.ServiceRegistryPerformer, cOne">
    <property name="ServiceRegistry" ref="ServiceRegistryProxyFactory"/>
    <property name="LocalServices">
      <dictionary key-type="string" value-type="Harkon.AppServer.cOne.Service.IService, cOne">
        <entry key="WillUse" value-ref="WillUse"/>
      </dictionary>
    </property>
  </object>

  <!--
  Service Proxy for IDoStuff
  -->

  <object id="DOStuffProxyName" type="Harkon.AppServer.cOne.Service.ServiceName, cOne">
    <constructor-arg index="0" type="string" value="DoStuff"/>
    <constructor-arg index="1" type="string" value="ComponentC"/>
    <constructor-arg index="2" type="string" value="ComponentC.IDoStuff"/>
  </object>

  <object id="DoStuffProxy" type="Harkon.AppServer.cOne.Service.ServiceProxy, cOne">
    <constructor-arg name="serviceName" ref="DOStuffProxyName" />
    <property name="ServiceRegistry" ref="ServiceRegistryProxyFactory"/>
  </object>

  <object id="DoStuffProxyFactory" type="Harkon.AppServer.cOne.Service.ServiceProxyFactory, cOne" factory-method="CreateServiceProxy&lt;ComponentC.IDoStuff>">
    <constructor-arg name="interceptor" ref="DoStuffProxy"/>
  </object>
  
</objects>


Okay, so what is new now...
  • In the spring config file after the service registry performer comes the part of the proxy to the destination service.
    • First the config file contains a service name configuration for the destination service
    • Then comes the proxy from the castle framework. The proxy (a class from the infrastructure) needs in the construction the service name and the reference to the service registry (a proxy again).
    • The proxy will be created during wire up via the proxy factory

Here the sequence diagram connecting the proxy to the real implementation during first time use:


back

Last edited Jun 4, 2010 at 8:34 PM by harkon, version 9

Comments

No comments yet.