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

Reply via email to