1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Tuscany Java Runtime Assembly</title>
</head>
<body>
<h1>Assembly</h1>
<h2>Introduction</h2>
<p>This document details how the Java Runtime performs assembly. Assembly is the process of
wiring networks of services based on external configuration. Assembly may occur both
locally (i.e. Between two services in a shared memory space) and remotely. Wires between
two services within the same aggregate context are local; wires whose target is an
external service or external URI are remote. Remote wires always follow pass-by-value
semantics. Local wires generally follow pass-by-reference except when the component
implementation contract declares otherwise.</p>
<h2>Local Assembly</h2>
<p>The Tuscany Java Runtime (TJR) attempts to precompute as much as possible of the assembly
model when a configuration is registered. This process is termed the build phase. During
this phase, the runtime walks the configuration (typically consisting of module
components, components, entry points, and external services) and calls all registered
implementations of o.t.core.builder.RuntimeConfigurationBuilder which in turn decorate
the configuration with implementations of o.t.core.builder.RuntimeConfiguration
(examples include the implementations in o.a.t.container.java.config and
o.a.t.container.java.builder). RuntimeConfigurations are factories for creating instance
contexts based on the corresponding configuration artifact. For example, an SCA Java
component will be decorated with a RuntimeConfiguration that can produce an instance
context which manages a POJO injected with the appropriate properties and references as
defined by the configuration.</p>
<p>The strategy for how a runtime configuration creates an instance context is specific to
the implementation type. For example, the SCA Java client implementation uses
o.a.t.core.injection.PojoObjectFactory to create POJOs. This in turns uses
implementations of o.a.t.core.Injector to inject properties and references during
instantiation (the injectors are created during the build phase by
o.a.t.container.java.builder.JavaComponentContextBuilder). Injectors are configured with
implementations of o.a.t.core.injection.ObjectFactory to create or return a property or
reference value. For example, reference values will have an injector that uses a factory
such as o.a.t.core.injection.ReferenceTargetFactory which is capable of creating a proxy
to the target service. In cases where a proxy is not needed, a factory may return the
actual target instance.</p>
<h2>Remote Assembly - TBD</h2>
<h2>Runtime Assembly</h2>
<p>Runtime assembly is the process of wiring components which offer special services in the
runtime. Runtime assembly is done in a manner similar to the standard assembly described
above, except that system components have their own implementation type (cf.
o.a.t.core.system). The system implementation type supports all SCA Java Client and
Implementation model constructs (properties and references), metadata, and stateless and
module scope lifecycles (request and session scopes are not currently supported but they
could be added if needed). In addition, the system implementation type also supports the
following capabilities:</p>
<ul>
<li><i>Autowiring.</i> Autowiring provides the ability to resolve reference targets
based on interface type. This is used to resolve targets where the actual target
component is not important (or should remain unknown) as long as it provides the
required service, for example, a transaction manager or monitor factory. Autowire
targets must be configured in a system module component external to the source
component (otherwise one would use "regular" wiring). An autowire target must be
published as an entry point using the special "system" binding. Further, autowire
entry points are only visible to the parent aggregate context and its children. To
make an autowire entry point visible more than one level up in an aggregate
hierarchy, it must be republished as an entry point by the parent aggregate context.
The following demonstrates how autowiring occurs:<p/>
<img src="assembly/Slide1.png" alt="autowire"/>
<p>To understand autowiring in more detail, review
o.a.t.core.system.SystemAggregateContextImpl,
o.a.t.core.context.AggregateContextImp, and
o.a.t.core.system.builder.SystemComponentContextBuilder.</p>
</li>
<li><i>ParentContext.</i> System components can also contain references to their parent
aggregate context. This is done through the "ParentContext" metadata (e.g.
<code>@ParentContext</code></li>
</ul>
<h3>Hierarchical Runtime Assembly</h3>
<p>The TJR essentially assembles itself from a series of "system" components in a recursive
fashion. Aggregate contexts are created from Module Components which in turn contain
children that are assembled (other aggregates, simple components, entry points, and
external services). Aggregate contexts may also be autowired (e.g.
o.a.t.core.context.AggregateComponentContextImpl). Child aggregate contexts are managed
by a special scope context, o.a.t.core.context.scope.AggregateScopeContext. This allows
the runtime to assemble itself using a relatively lightweight builder infrastructure to
an arbitrarily deep nesting. For further details see o.a.t.core.system.builder and
o.a.t.core.system.config.</p>
</body>
</html>
|