FITECH Laboratories spacer
graphic Company graphic Products graphic Support graphic Customers graphic Partners
The Power of Choice
spacer » Buy graphic » Try graphic » Map graphic » Contact graphic
spacer
spacer
xTier™
Overview
xTier Services
Business Case
Documentation
F.A.Q.
Buy xTier™
Try xTier™
Professional Services
graphic
spacer xTier
spacer
ioc
Product: xTier™/LWC 2.3
Whitepaper:  Technical Whitepaper
spacer
 support@fitechlabs.com
 Download
 Buy
 Depends: n/a
 Related: log
xTier™ Navigator:
cache cluster config email i18n
ioc info jmx jndi security
log marshal objpool os fs
tx uidgen workflow jobs
db startup jms grid

Description
Inversion Of Control (IoC) is a well known design pattern that is generally used for configuring components' dependecies. It is also know as the "Hollywood Principle - Don't Call Us We'll Call You" (introduced at Mesa Programming Environment) or, as more strictly defined, by Martin Fowler - "Dependency Injection".

Despite the various definitions for IoC, in a nutshell, it can be described as follows: Say we have two components A and B, and A depends on (uses) B. In a conventional scenario (i.e. without IoC) A will need to explicitly obtain B and establish its dependecy on it. Using an IoC design pattern, however, a system could automatically obtain and establish the dependency on B without any explicit request on the part of component A - hence reversing (inverting) the control of dependency. Following diagram illustrates this definition:

IoC is not the only way to make dependency control indirect. The Service Locator design pattern provides another way to decouple dependency control from a component (and not only in J2EE applications). However, there is still a significant difference between IoC and Service Locator as Service Locator requires an explicit request from the component to locate the dependency hence coupling component to a specific Service Locator interface, whereas in IoC case no explicit interaction is required and no coupling is created.

There are several types of IoC implementations that are currently available today (terminalogy from Martin Fowler):

Type 1 (interface injection)
This type of IoC is based on providing a specific inteface for each specific instance of dependency injection (i.e. for each component that needs that behavior). At runtime these interfaces will be analyzed and proper dependencies will be set for each component. The major problem with this aproach is that it requires too many "marker" interfaces to be created which leads to heavy maintaince requirements and a poluted design. The inteface injection type of IoC is used by the open source Avalon framework. One of the distinct capabilities of such an approach is that its implementation does not require an external, non-Java configuration.
Type 2 (setter injection)
In this type of IoC dependency injection is achived by setting certain properties using a JavaBean type of convention. Usually, the specific properties are defined in an XML file and at startup or per request they are set or "wired-up" to form a dependency. This is a most common type of IoC and used by variety of software systems including some open source frameworks such as Spring and PicoContainer.
Type 3 (constructor injection)
Unlike Type 1 and Type 2, Type 3 of IoC makes use of constructors to pass in a component's dependencies instead of using setters or per-component injection interfaces. Although, seemingly an elegant solution that should, in theory, lead to a better design by enforcing that each component is fully initialized during creation, the real applicability of Type 3-only IoC is very limited. In fact, it goes against the very nature of IoC as it basically requires each component to be designed to fit such an arrangement, which defeats the purpose of decoupling dependency control from a component. Thus most of the IoC implementation use some combination of Type 3 and Type 2 or Type 1. The PicoContainer provides an attempt to develop an almost Type 3-only IoC system.

 Top

IoC in xTier™
xTier™ provides IoC functionality in two distinct ways:

  • Configuration for each service provided by xTier™ is based on IoC. Every XML configuration file uses the same syntax and semantic to define IoC components that are used in the configuration of a particular service. See XtierKernel for more information on services configuration.
  • xTier™ provides an 'ioc' service that exposes full IoC functionality and features to the developer allowing the developre to create highly configurable and flexible software systems.
Note that in both cases the 'ioc' service and other configurable xTier™ services use exactly the same semantic and configuration for defining IoC components (with one exception that is noted below).

xTier™ 'ioc' provides combination of traditional Type 2 and Type 3 types of IoC with some additional unique features:

  • Support for 'new', 'singleton' and user-defined 'keyed' creation policies. The user defined "keyed" policy allows, for example, creation of an IoC object per-thread by using the current thread as a key when creating the IoC object.
  • Generalized support for setters and init methods. 'ioc' allows calling any arbitraty methods on the object as long as its signature can be properly constructed. That feature is extremely important for supporting "legacy" components that may require the constructor call, setting one or many parameters via JavaBean type of setters or via other non-compliant methods and then calling one or more initialization methods that may also take arbitrary input parameters. Furthermore, certain calls must be performed in a certain order, repeated or intermixed with each other.
    For example, 'ioc' can create an IoC object as a java.util.ArrayList with certain size passed into constructor, populate it with certain pre-defined values via calls to add(java.lang.Object) or add(int, java.lang.Object) methods, call trimToSize() and pass this object to another IoC object as a parameter.

 Top

Configuration
The 'ioc' service acts as a factory for IoC objects. IoC objects are defined in the xtier_ioc.xml configuration file. This file follows the standard xTier™ service configuration pattern and is illustrated by the following complete example of IoC object definition:

1<!-- Simple java.lang.String IoC object. -->
2<ioc uid="string" policy="new">
3  <java class="java.lang.String">
4    <ctor>
5      <arg type="string">xTier</arg>
6    </ctor>
7  </java>
8</ioc>
9
10<!-- Reference IoC object. -->
11<ioc uid="ref" ref-uid="string"/>
12
13<!-- 
14    java.lang.StringBuffer IoC object that 
15    uses "ref" IoC object. 
16-->
17<ioc uid="str.buf" policy="singleton">
18  <java class="java.lang.StringBuffer">
19    <ctor>
20      <arg ref-uid="ref"/>
21    </ctor>
22  </java>
23</ioc> 

It is important to note that all following explanations about <ioc> XML tags equally apply to any other xTier™ service that uses IoC functionality for its configuration or logic. Remember that the IoC semantic and syntax are identical in all xTier™ services including 'ioc'. The 'ioc'service just directly exposes IoC-only functionality to the end user.

The 'ioc' service configuration consists of one or more IoC descriptor definitions specified by the <ioc> tag.

The formal specification for the <ioc> tags can be found in the xtier_dtd_includes.dtd DTD file in the ${XTIER_ROOT}/config/dtd folder. <ioc> tag supports the following attributes:

uid This attribute defines the Unique ID of the IoC descriptor. This attribute is mandatory.
policy This attribute defines the creation policy for the IoC descriptor:
  • new - An IoC descriptor with this creation policy will create a new IoC object every time the method makeIocObject(String) or makeIocObject(String, Object) is called.
  • singleton - An IoC descriptor with this creation policy will create a new IoC object only the first time. All subsequent calls to the method makeIocObject(String) or makeIocObject(String, Object) will return the same instance.
  • keyed - An IoC descriptor with this creation policy will create only once instance for each key specified in the makeIocObject(String, Object) method call. NOTE: this creation policy is only allowed in the 'ioc' service itself. All other xTier™ services can use the 'new' or 'singleton' creation policy but not the 'keyed'.
Note that this attribute cannnot be used together with the ref-uid attribute.
ref-uid This attribute defines a referenced IoC descriptor. When ref-uid attribute is defined this IoC descriptor basically acts as an alias for the referenced IoC descriptor. Note that this attribute cannot be used together with the policy attribute.

The <ioc> tag consists of either the one <java> or one <clr> tags that define how the IoC object should be created. There are two general ways how an IoC object can be created: user can specify the name of the class and the instance of that class will be created, or user can specify the other IoC descriptor and the method name that both would act as a factory for creating new IoC objects defined this descriptor.

In first case user just specifies fully qualified class name in class attribute, and in the second case user provides factory UID and method name via factory-uid and method attributes:

class Fully qualified class name. Objects of this class (see also the <ctor> tag for constructor definition) will be created when IoC descriptor creates new object. This attribute cannot be mixed with factory-uid and method attributes.
factory-uid This attribute defines UID of another IoC descriptor that will serve as a creation factory for this IoC descriptor. Note that factory-uid and method attributes must always be used together. Note also that these attributes cannot be used together with class attribue.
method Name of the method that will be called on the object created by IoC descriptor referenced by factory-uid attribute to create new IoC object. The mmethod must take no arguments and return type java.lang.Object. Note that factory-uid and method attributes must always be used together. Note also that these attributes cannot be used together with class attribue.

<java> tag consists of an optional <ctor> tag defining the constructor call and zero or more <call> tags defining method calls to be performed on the constructed object. Each <ctor> and <call> tag consists of zero or more <arg> tags that define the actual argument of the constructor or a method call. <ctor> tag has no attributes, while <call> tag has one attribute method defining what method to call on the constructed object. Note that if <ctor> tag is not specified the class is expected to have accessable no-arg constructor.

<arg> tag has the following attributes:

null Value true or false indicates whether or not this argument is null. The default value specified in DTD for this attribute is false.
boxed Value true or false indicates whether or not this argument is a boxed type. For example, if this attribute is true and the type attribute is int32 the expected signature type for a constructor or method call will be java.lang.Integer. The default value specified in DTD for this attribute is false.
type This attribute specifies the type of the argument. The table below shows all supported types and their Java counterparts in boxed and unboxed form:

IoC Type Unboxed Boxed
int8bytejava.lang.Byte
int16shortjava.lang.Short
int32intjava.lang.Integer
int64longjava.lang.Long
float32floatjava.lang.Float
float64doublejava.lang.Double
charcharjava.lang.Character
booleanbooleanjava.lang.Boolean
string - java.lang.String
date - java.util.Date
ref-uid This attribute specifies that the argument is a reference to another IoC descriptor whose value will be used as a this argument's value. This attribute is the essence of establishing the dependency by one IoC descriptor to another. Note that circular references are not allowed. ref-uid attribute can only be used together with null attribute. If null attribute is set, then null value be used.
const This attribute allows to use static field in the class as an actual argument's value. The value of this attribute must be specified in the form className#fieldName, where className must be a fully qualified class name.
Note that this attribute cannot be used with any other attributes in the <arg> tag.

 Top

Examples
Usage of the 'ioc' service follows the standard pattern of using an xTier™ service: you need to obtain an instance of the xTier™ kernel that serves as a service registry. Once you have the xTier™ kernel you can get an instance of any service, in our case the 'ioc' service. Assume that we have the following IoC definition:

1<ioc policy="new" uid="str">
2  <java class="java.lang.String">
3    <ctor>
4      <arg type="string">xTier</arg>
5    </ctor>
6  </java>
7</ioc>
8
9<ioc policy="keyed" uid="list">
10  <java class="java.util.ArrayList">
11    <ctor>
12      <arg type="int32">4</arg>
13    </ctor>
14
15    <call method="add"><arg type="int32" 
16        boxed="true">1</arg></call>
17    <call method="add"><arg type="int32" 
18        boxed="true">2</arg></call>
19    <call method="add"><arg type="int32" 
20        boxed="true">3</arg></call>
21    <call method="add"><arg ref-uid="str"/>
22  </java>
23</ioc> 

With this configuration we can create a thread-local populated list using the following code:

1// Get the instance of xTier kernel.
2XtierKernel xtier = XtierKernel.getInstance();
3 
4// Get the instance of 'ioc' service.
5IocService ioc = xtier.ioc();
6 
7// Use 'ioc' service.
8List list = (List)ioc.makeIocObject("list", 
9    Thread.currentThread());

 Download xTier™ for full examples and documentation.

 Top

spacer