Component types
Immediate component
A component is an immediate component if it defined the property "immediate": true
and is not a factory component.
A component is treated as immediate if it does not declare a "provides"
property.
{
"name" : "MyComponent",
"provides" : ["myservice.Interface"],
"immediate": true
}
If the component has no references, you can consider the lifetime of the component as equal to BundleActivator, which is created on the start of a bundle and destroyed during the stop of the bundle.
Only immediate components are allowed to act asynchronously in their activation method.
This means that a component instance is allowed to return a dojo.Deferred
during its activate()
method and the App Runtime waits until activate()
finishes before it registers the component instance as a service at the App Runtime.
Delayed component
A component description which declares a "provides"
property and which is not an immediate component and not a factory component is treated as delayed.
This means that delayed components are the most common kind of components, because this is the default case if no other special property is declared.
{
"name" : "MyComponent",
"provides" : ["myservice.Interface"]
}
Delayed components are so named because of the fact that service registration is made before the component instance is created. This means that the creation of the component instance is delayed until the first use of the registered service. A delayed component instance is destroyed if it becomes unused. As a result, delayed components can have a very dynamic life because construction and destruction might happen very often and are highly dependent on usage of the service provided by the component.
If a delayed component declares the property "serviceFactory": true
, the App Runtime creates a new service instance for each requesting bundle.
Factory component
A component description which specifies the property "componentFactory": true
is treated as factory component.
{
"name" : "MyComponent",
"provides" : ["myservice.Interface"],
"componentFactory" : true
}
A factory component is a special design pattern, because it acts more as a template for the dynamic creation of component configurations based on component descriptions.
The App Runtime parses the component description.
If it is satisfied, it registers a service with the interface ct.framework.api.ComponentFactory
for this configuration.
This service provides a method newInstance
, which can be used to create new component configurations during runtime.
This newInstance
method returns a ComponentInstance object, which provides the method getInstance
for accessing the real instance, and the method dispose
for shutting down the component configuration.
The caller of newInstance
is responsible for the disposal of the created component configuration.
// Activator using a component factory
export default class{
start(bundleContext) {
// search special component factory with name "MyComponentFactory"
let references = bundleContext.getServiceReferences("ct.framework.api.ComponentFactory","(Component-Name=MyComponent)");
try {
// get the component factory service
let factory = bundleContext.getService(references[0]);
// create a new component configuration
// here the default component properties defined in the declaration of the component factory can be overwritten.
let componentInstance = factory.newInstance({ "aproperty": "newValue" });
// get component/service implementation
// this feature should rarely be used, better define a reference
let impl = componentInstance.getInstance();
impl.doSomething();
// the created component configuration has to be cleaned up later
componentInstance.dispose();
} finally {
bundleContext.ungetService(references[0]);
}
}
}
Factory Components are a very powerful feature because the newInstance
method creates new component configurations.
This means that such a new dynamically created component configuration is managed by the App Runtime as if it were a new and independent component description in the manifest.json
file.
Therefore if the property provides
is specified, the new component instance is registered as a service in the App Runtime.
Because of the ComponentInstance.getInstance
method, a component configuration created by a factory component is treated as an immediate component, therefore, regarding its using state, the component instances are directly created.
An important point is that a factory component is satisfied if all references of the component description are also satisfied.
In some circumstances this definition leads to unexpected behaviors especially if references are using placeholders in filter expressions.
// Other component using a component factory
// manifest.json
{
"name" : "OtherComponent",
"references" : [{
"name" : "_factory",
"providing" : "ct.framework.api.ComponentFactory",
"filter": "(Component-Name=MyComponent)"
}]
}
// implementation of OtherComponent
export default class {
activate() {
// create a new component configuration
// here the default component properties defined in the declaration of the component factory can be overwritten.
let componentInstance = this._factory.newInstance({ "aproperty": "newValue" });
// get component/service implementation
// this feature should rarely be used, better define a reference
let impl = componentInstance.getInstance();
impl.doSomething();
// the created component configuration has to be cleaned up later
componentInstance.dispose();
}
}