A lightweight Java component model and runtime container.
Home | Previous: Step 7: Structuring Components | Next: Step 9: Next Steps
Real applications rarely start from a blank page. They already contain objects that were not written for Covalent: existing classes, objects created by another framework, objects owned by a UI toolkit. Covalent can integrate such objects without rewriting them, as raw components.
A raw component is an externally owned object registered in the container. Unlike a
managed component, it is instantiated by its owner, it has no Covalent annotation,
and its ports are declared explicitly through the container’s RawComponentsServices
instead of by annotations.
Here is a plain Java class that implements a plain Java interface. Neither has any reference to Covalent:
public interface StockServices {
int quantityInStock(String product);
}
public static final class ExistingStock implements StockServices {
The integration happens at the boundary of the application, through
container.rcs():
rawComponents.registerComponent(stock);
registerComponent(...) registers the existing instance; by default, its component
type is its class, and it is brought to the activated state.
rawComponents.provideServices(ExistingStock.class, StockServices.class);
provideServices(...) declares that it provides StockServices; the component
type is given explicitly because the provider is a raw component.
From then on, a managed component uses the service like any other, with a
@UsedServices field. It does not know, and does not need to know, that the
provider is a raw component:
@UsedServices
private StockServices useStockServices;
Important:
RawComponentsServicesis meant to interface with the non-Covalent world. It rejects classes that carry Covalent annotations: components written for Covalent must be deployed as managed components.
package tutorial;
import org.opales.covalent.Covalent;
import org.opales.covalent.container.CovalentContainer;
import org.opales.covalent.container.component.annotations.Component;
import org.opales.covalent.container.component.annotations.Implementation;
import org.opales.covalent.container.component.annotations.UsedServices;
import org.opales.covalent.container.lifecycle.Activation;
import org.opales.covalent.container.raw.RawComponentsServices;
public final class Step8 {
// --- A plain Java interface: no Covalent annotation, since it is the contract
// of a non-Covalent object ------------------------------------------------
public interface StockServices {
int quantityInStock(String product);
}
// --- An existing object: no Covalent annotation, no Covalent import needed
// other than the raw services used to declare its ports ----------------
public static final class ExistingStock implements StockServices {
@Override
public int quantityInStock(final String product) {
return "coffee".equals(product) ? 42 : 7;
}
}
// --- A managed component using the existing object's service ------------------
@Component
public interface Shop {
}
@Implementation
public static final class ShopImpl implements Shop {
@UsedServices
private StockServices useStockServices;
@Activation
public void openShop() {
System.out.println("Coffee in stock: " + this.useStockServices.quantityInStock("coffee"));
}
}
public static void main(final String[] args) {
CovalentContainer container = Covalent.main;
RawComponentsServices rawComponents = container.rcs();
ExistingStock stock = new ExistingStock();
try {
// 1. Register the existing object. Its component type is its class.
rawComponents.registerComponent(stock);
// 2. Declare the service port it provides.
rawComponents.provideServices(ExistingStock.class, StockServices.class);
// 3. Managed components are deployed and started as usual.
container.deployComponents(ShopImpl.class);
container.start();
} finally {
if (container.isStarted()) {
container.stop();
}
}
}
}
Its output:
Coffee in stock: 42
Raw components can do the reverse and more: use services of managed components, offer and access parameters, produce and subscribe to events, follow the lifecycle callbacks, and be unregistered. This makes it possible to bring an existing application into Covalent one object at a time. Raw components have a runtime cost that managed components do not, which is documented in Performance Characteristics.
Reference: Raw Components Guide, Managed and Raw Components.
Home | Previous: Step 7: Structuring Components | Next: Step 9: Next Steps