I've added today the possibility to define services inside XML
components using the
tags defined by OSGi.
So you can define a service like this:
<service>
<provide
interface="org.nuxeo.runtime.services.deployment.DeploymentService" />
</service>
You can specify one or more interfaces (through the tag provide)
OSGi defines several type of components - immediate, delayed and factory
components.
Currently, NXRuntime components behaves like OSGi immediate components -
they are activated when
all prerequisites are met (when dependencies are resolved)
How services declared by a NXRuntime component are handled?
First lets talk a little about the role of NXRuntime components in the
system and what exactly are them.
Although they are very closed to OSGi components NXRuntime components
have their own features and behaviors that may not be OSGi compliant.
So what is a NXRuntime component?
From wikipedia: /A component is a system element offering a predefined
service and able to communicate with other components.
/NXRuntime components are conform to that definition.
So a NXRuntime component is a piece of software that may expose one or
several services and may communicate with other components
at deployment (setup) time through extension points and at runtime using
NXRuntime event service or any custom event service.
Until now a component exposed a single service - the component itself
could be considered a service.
Now, because declaring service interfaces is possible inside the XML
descriptor of the component a component may expose several
functionalities as services (as declared by the <service> tag)
So a component may be itself a service or it may manage and expose one
or several services.
Also, in NXRuntime a component may even not exists as a java class. This
means the <implementation>
declaration is not required by NXRuntime.
Why? because you may want to create components only for configuring
other components through extension points.
So you can have a component with no implementation that is only
declaring extensions to other components.
Another addition of NXRuntime components are the extension points and
the capability to contribute extensions to other components
in the system.
I think now it is clear what is a NXRuntime component.
So how services are handled by NXRuntime components? (services declared
through the OSGi <service> element)
The runtime service (the SCR equivalent) is managing a service registry
The service registry is mapping service class names to RegistrationInfo
objects which describes the component that declared the service
(RegistrationInfo objects are component description and they are created
directly from the XML component file)
So when someone wants to get the service that implements
EventService.class (full name is
org.nuxeo.runtime.services.event.EventService)
NXRuntime will look into the registry and will find the component that
declared this service and then it will ask that component to return
the service instance object.
The service instance may be the component itself so the component will
return a reference to itself in this case.
If the service is a member of the component the component will return
that member or it may also make its own lookup to get the service
instance .. How the service is retrieved is up to the component
implementation.
When a component declares multiple services it should pick the right one
that match the service class passed by the caller.
Here is an example of how the service instance is retrieved by NXRuntime:
-> RuntimeService.getService(EventService.class) is called
-> ComponentManager.getService(EventService.class) - the call is
delegated to the component manager that keeps the service registry
The manager is getting the RegistrationInfo object of the component
declaring the service: EventService.class
and delegates to it the service lookup
-> RegistrationInfo.getComponent().getAdapter(EventService.class) is called
The ComponentInstance object is a proxy to the real component instance
as declared by the <implementation> element in the XML component file.
The ComponenInstance is querying now the real component object about the
service. The following method is used:
- if the real component is implementing the Adaptable interface then the
service is looked up using:
component.getAdapter(EventService.class)
- othewrise if the component object type is compatible with given one
(i.e. EventService.class) a dynamic cast is made and the component
object itself is returned
- otherwise null is returned.
So, the recommended way for a component to expose services is to
implement the interface Adaptable and define the method
public <T> T getAdapter(Class<T> serviceClass);
When extending DefaultComponent this interface is automatically
implemented.
Let's look at the EventService component. The component is exposing
EventService.class itself as a service. So its getAdapter() method looks
like this
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapter) {
return adapter == this.getClass() ? (T)this : null;
}
Lets say you have now a component MyComponent that expose 2 services
TypeManager.class and ActionManager.class
You can write the getAdapter() method like this:
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapter) {
if (adapter.isAssignableFrom(TypeManager.class)) {
return typeManager;
} else if (adapter.isAssignableFrom(ActionManager.class)) {
return actionManager;
} else {
return null;
}
}
And so the client to get the instance of the TypeManager service will
make the following lookup:
TypeManager typeManager =
NXRuntime.getRuntime().getService(TypeManager.class);
and that's all.
Bogdan
P.S.
So please update your NXRuntime components and declare any service you
want to be available locally through NXRuntime
_______________________________________________
ECM mailing list
[email protected]
http://lists.nuxeo.com/mailman/listinfo/ecm