CUBA Component Model


The component and programming model for CUBA components closely follows the EJB 3 SessionBean model. This is a matter of nature due to the fact, that the EJB standard defines the most powerful component model available for Java-based systems. The API looks 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 which 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. The only non-compatible difference in the API is that the propriatery interface cuba.SQLSourceI 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.

Lifecycle Management

A CUBA component has the same lifecycle as a Stateless SessionBean from the EJB standard, being managed by either an EJB container (when running the 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

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 JEE SessionContext.

Transaction Managment

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 Access.

Database access

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 embedded container provides its own simple resource management including a connection pooling 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).

Callchain Management

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' application server functionality in unmanaged environments. Future extensions e.g. for container-managed security will be based on this feature. The devloper usually does not have to know about this technical detail.

Single-Thread Model

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 up in CUBA as well. However, there is an important detail to know: while the wired container is completely thread-safe, the generated wired adapters are not. As a consequence, it is in the responsibility of the programmer not to share one component reference by multiple threads. As any component lookup returns a new adapter, it should be very easy to ensure this condition.

Deployment Descriptors

As it is known from the EJB standard, CUBA components are described by a set of annotations, declared in an XML-based deployment descriptor. The source descriptor is independent from the target environment and only serves as 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 container needs an application-level descriptor like the application.xml of a JEE application.
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.

Environment Entries

Basic component configuration can be achieved by environment entries, i.e. named values, defined in a component's deployment descriptor. See chapter Environment Entries for details.

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 any base interface, one interface class can be used as both internal and external interface as long as all method signatures are suitable (i.e. all parameters are serializable and interoperable). This is especially useful when building up a catalogue of reusable components which must efficiently be accessed in different contexts.

Security

CUBA currently only supports component-managed security based on the functions getCallerName() and isCallerInRole() 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 chapter Security for details.

Method interceptors

Method interceptors can be defined in the same way as in the EJB standard using the code annotation @AroundInvoke or the descriptor element around-invoke. Method interceptors in CUBA get passed a cuba.InvocationContextI which is an equivalent to J2EE's InvocationContext interface.

API

Not regarding the differences between the capabilities of an EJB container and the simple embedded container, the programming model is completely identical in every environment. Components can be developed in one and safely be run in any other supported environment. This is one of the key features of CUBA.
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.

Asynchronous Invocation

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 invoked from a self-written JMS consumer.


Home Introduction Javadoc