CUBA Component Model
The component and programming
model for CUBA components closely follows the EJB 3 SessionBean model.
is a matter of nature due to the fact, that the EJB standard defines
most powerful component model available for Java-based systems. The API
a little different sometimes to keep it independent from using it only
within a J2EE 5 environment. E.g. all code annotation types known from
the EJB 3 model have been redefined in package cuba.annotation and some have
been renamed to better express a concept rather than a technical issue
(like "External" instead of "Remote"). Nevertheless, developing CUBA
components is just like developing version 3 EJBs. This chapter
explains the central aspects of the CUBA component model
in relation to the EJB 3 model which are important to know for
efficient programming. In addition it is very helpful to have a look at
CUBA's JUnit test suite if there occur any questions in practical use.
Notes for users of CUBA version 1 and 2
Cuba version 1 and 2 already applied the most important improvements
came up in the EJB model with version 3. Therefore, the CUBA 3 model is
almost completely compatible with the CUBA 1 model. Migrating from CUBA
1 or 2 usually only requires to regenerate adapters and descriptors.
only non-compatible difference in the API is that the propriatery
from CUBA 1 has been removed and substituted by the Java standard type javax.sql.DataSource. Since DataSource has been moved to
the Java core API, it can be used without becoming dependent on JEE.
All functions of the older interface SQLSourceI are available in DataSource too, so any
migration work at this point is fairly simple.
A CUBA component has the same lifecycle as a Stateless SessionBean from
EJB standard, being managed by either an EJB container (when running
component as an EJB) or by CUBA's wired container for all other
environments. Components may be declared stateful but do not have
support for activation and passivation yet as it is known from EJBs.
Lifecycle callback functions can optionally be defined by PostConstruct and PreDestroy annotations in the
code or in the XML descriptor. As an alternative, a component may
implement the interface ComponentI which defines a
minimal set of default lifecycle methods as they are known from
CUBA 1 (respectively from interface javax.ejb.SessionBean in EJB
2.1). In this case it is recommended to use the base class AbstractComponent for
convenience purposes, which defines empty implementations
for init() and drop() and
keeps the component context passed in setContext()
as a member. Lifecycle control can also be seperated from a component's
implementation class by means of interceptors. Interceptor
classes work exactly as it is specified in the EJB 3 standard.
Stateful components with container-managed transactions may implement
the interface cuba.StateSynchronizationI
to get informed about the begin and the completion of transactions the
component participates in. The interface defines identical methods as javax.ejb.SessionSynchronization
and has been redefined for the sake of independence from J2EE in every
development and runtime environment supported by CUBA.
Dependency injection in CUBA is the same as in the EJB 3 model. As a
tiny difference, a reference to another component is expressed by the
code annotation @Component
or the descriptor element component-ref
rather than @EJB and ejb-ref. If you
prefer lookups for components and resources, CUBA's container provides
the interface ComponentContextI.
In EJB mode, this is only a compatibility wrapper for the underlying
Transaction boundaries can be set by a component itself fetching the
current transaction context by function ComponentContextI.getTransaction().
A more convenient way is to use container-managed transactions being
declared on method level in a component's deployment descriptor.
Details are described in chapter Database
CUBA provides basic access to SQL databases by means
of the interface javax.sql.DataSource.
In an EJB environment, the actual
resource management is delegated to the application server. The
provides its own simple resource management including a connection
facility. Details are described in chapter Database Access. Convenient
access is provided by the Java Persistence API, which is also supported
by CUBA (see chapter JPA).
Container-managed transactions in a wired container are based on a
general callchain management propagating a transaction and security
context down the
component call stack. This allows the wired container to 'emulate'
server functionality in unmanaged environments. Future extensions e.g.
container-managed security will be based on this feature. The devloper
does not have to know about this technical detail.
Like in the EJB component model, CUBA components can rely on a
single-thread model for the implementation class and are not allowed to
spawn any threads on their own behalf. Single thread programming for
server components is one
of the biggest simplifications in EJB development and therefore is kept
in CUBA as well. However, there is an important detail to know: while
wired container is completely thread-safe, the generated wired adapters
not. As a consequence, it is in the responsibility of the programmer
to share one component reference by multiple threads. As any component
returns a new adapter, it should be very easy to ensure this condition.
As it is known from the EJB standard, CUBA components are described by
set of annotations, declared in an XML-based deployment descriptor. The
descriptor is independent from the target environment and only serves
the input for the descriptor generator to generate either EJB standard
descriptors or descriptors for the wired container. The descriptor at
least mentions the
component name, interface and implementation class. Additional content
are e.g. configuration parameters (see chapter Environment Entries), depedency
injections and container-managed transaction
attributes (see chapter Database
Access). Users of a Java 5 environment may specify all meta
information for a component by means of Java code annotations as well.
Both description styles are fully equivalent and produce the same
output from CUBA's code and descriptor generators.
CUBA's embedded container solely uses the generated
XML descriptors to make it work in both JDK 1.4 and Java 5
environments. In addition to component descriptors, the embedded
application-level descriptor like the application.xml of a JEE
The generated EJB 3 adapters are based completely on code annotations,
not regarding wether the CUBA component uses XML or code annotations.
This allows to override the component's configuration details by an EJB
deployment descriptor without changing the CUBA descriptor or CUBA
annotations. For EJB 2.1 adapters, the generated deployment descriptor
ejb-jar.xml is mandatory. The file name is defined by the EJB standard
and is the same as for EJB 3 alltough it is not fully compatible. A
component JAR can therefore not by equiped with adapters being suitable
for both EJB 2.1 and EJB 3 while there is no interference with the
adapters (and descriptors) for webservice and wired mode.
Basic component configuration can be achieved by environment entries,
named values, defined in a component's deployment descriptor. See
Environment Entries for
Internal und external Interfaces
A component may have defined an internal
and an external interface.
Internal interfaces can only be used within the component container
having a call-by-reference semantic. External interfaces can also be
used by clients outside the container
and have a call-by-value semantic, no matter if the interface is later
accessed through interprocess communication or from within the same
process. Due to
tha fact, that CUBA component interfaces do not have to be derived from
base interface, one interface class can be used as both internal and
interface as long as all method signatures are suitable (i.e. all
are serializable and interoperable). This is especially useful when
up a catalogue of reusable components which must efficiently be
in different contexts.
CUBA currently only supports component-managed security based on the
in interface ComponentContextI.
In EJB environments, these functions are based on the appropriate
functions in interface EJBContext which in turn are based on
JAAS. The wired container follows a much simpler approach, assuming
authentication is either not required at all or is performed before
actually accessing the components.
Container-managed security will be added in future CUBA releases. See
Security for details.
Method interceptors can be defined in the same way as in the EJB
standard using the code annotation @AroundInvoke or the descriptor
Method interceptors in CUBA get passed a cuba.InvocationContextI
is an equivalent to J2EE's InvocationContext
Not regarding the differences between the capabilities of an EJB
container and the simple embedded container, the programming model is
in every environment. Components can be developed in one and safely be
in any other supported environment. This is one of the key features of
CUBA provides its own Java code annotation types rather than using the
ones from EJB 3. This is a matter of concept as CUBA components are
supposed to be completely independend from any of the target
environments. Additionally it would mess up the deployment if both, the
core implementations and generated adapters were EJB-annotated.
However, the available CUBA annotations are equivalent to what is
available in the EJB 3 standard.
CUBA defines a component model which is not necessarily based on a
server environment and therefore has no concept for asynchronous method
invocation as it is known from EJB's message-driven beans. If
asynchronous invocation is required, the actual core component must be
a self-written JMS consumer.