The simplest service is a bean annotated with @Service
.
package com.acme;
@Service
class Foo {
}
Unless otherwise specified, @Service
beans are published as follows:
- if the bean does not implement any interfaces, the service type is the bean type.
- if the bean implements any interfaces, the service types are all implemented interfaces.
The service above is registered with the service type com.acme.Foo
.
import com.acme.Bar;
import com.acme.Baz;
@Service
class Foo implements Bar, Baz {
}
The service above is registered with the service types com.acme.Bar
and com.acme.Baz
.
There are several ways to specify which service types @Service
beans are published.
- One or more types my be specified by applying the
@Service
annotation to type use clauses. - The
@Service
annotation on the bean type may specify a set of types as an argument of the annotation.
import com.acme.Bar;
import com.acme.Baz;
import com.acme.Fum;
class Foo extends @Service Fum implements @Service Bar, Baz {
}
The above example specifies that the bean should be published with service types com.acme.Fum
and com.acme.Bar
, but NOT com.acme.Baz
.
import com.acme.Bar;
import com.acme.Baz;
import com.acme.Fum;
@Service({Fum.class, Bar.class})
class Foo extends Fum implements Bar, Baz {
}
This example produces the same result as the previous example.
Unless otherwise specified, @Service
beans have singleton
service.scope
.
The example in the previous section produces a service at singleton
scope.
The annotation @ServiceInstance
is used to specify the service.scope
.
@Service
@ServiceInstance(PROTOTYPE)
class Foo {
}
Available values are SINGLETON
, BUNDLE
, and PROTOTYPE
.
Beans scoped @ApplicationScoped
or @Dependent
, as well as beans having the stereotype @SingleComponent
or @FactoryComponent
can be annotated with @Service
and become services.
@Service // Valid! @Dependent & singleton service
class Foo {
}
@Service // Valid! @ApplicationScoped & singleton service
@ApplicationScoped
class Foo {
}
@Service // Valid! @ComponentScoped & prototype service
@ServiceInstance(PROTOTYPE)
@SingleComponent
class Foo {
}
@Service // ERROR! Only @ApplicationScoped, @Dependent, @SingleComponent & @FactoryComponent can be services.
@SessionScoped
class Foo {
}
@Service // ERROR! @ApplicationScoped can only have singleton scope.
@ServiceInstance(PROTOTYPE)
@ApplicationScoped
class Foo {
}
Beans scoped @Dependent
(default when no scope annotation is defined on the bean), and beans having the stereotype @SingleComponent
or @FactoryComponent
can have any service.scope
.
Beans scoped as @ApplicationScoped
may only have service.scope
singleton
. However, such beans may directly implement ServiceFactory
or PrototypeServiceFactory
in order to provide service instances at bundle
, or prototype
service.scope
respectively.
Service properties may be added to @Service
beans by annotating them with annotations that are meta-annotated using @BeanPropertyType
. These annotations are then coerced into service properties following a predefined set of coercion rules as defined in the specification.
There are a number of predefined @BeanPropertyTypes
to handle common cases, such as @ServiceRanking
, @ServiceDescription
, @ServiceVendor
and @ExportedService
.
@Service
@ServiceRanking(100)
class Foo {
}
In addition to these, Aries CDI provides an additional suite of BeanPropertyTypes in the dependency org.apache.aries.cdi.extra
:
<dependency>
<groupId>org.apache.aries.cdi</groupId>
<artifactId>org.apache.aries.cdi.extra</artifactId>
<version>${aries-cdi.version}</version>
</dependency>
In all there exist BeanPropertyTypes for the Http Whiteboard, JAXRS Whiteboard, Event Admin and Remote Service Admin specifications.
Creating your own BeanPropertyTypes is very simply meta-annotating a runtime annotation with @BeanPropertyType
(since CDI uses runtime annotation processing, the annotations must have runtime retention).
@Retention(RUNTIME)
@BeanPropertyType
public @interface Config {
int http_port() default 8080;
}
Adding metatype annotations to your BeanPropertyTypes is the recommended way of providing a schema for your configuration(s).
@Retention(RUNTIME)
@BeanPropertyType
@ObjectClassDefinition(
localization = "OSGI-INF/l10n/member",
description = "%member.description",
name = "%member.name"
icon = @Icon(resource = "icon/member-32.png", size = 32)
)
public @interface Member {
@AttributeDefinition(
type = AttributeType.PASSWORD,
description = "%member.password.description",
name = "%member.password.name"
)
public String _password();
@AttributeDefinition(
options = {
@Option(label = "%strategic", value = "strategic"),
@Option(label = "%principal", value = "principal"),
@Option(label = "%contributing", value = "contributing")
},
defaultValue = "contributing",
description = "%member.membertype.description",
name = "%member.membertype.name"
)
public String type();
}
TODO
The simplest form of getting a service into a bean is with the @Reference
annotation (simple called a reference).
@Inject
@Reference
Bar bar; // using field injection
// OR
private final Bar bar;
@Inject
public Fum(@Reference Bar bar) { // using constructor injection
this.bar = bar;
}
// OR
private Bar bar;
@Inject
public void addBar(@Reference Bar bar) { // using method injection
this.bar = bar;
}
I want to get the service properties of the referenced service. Are there other service representations I can get in my reference that can help me?
There are a number of service representations that can be injected most of which provide a facility for getting the service properties:
-
S
- whereS
is the raw service type, this is the most basic form of reference@Inject @Reference Person person;
-
ServiceReference<S>
- you can get the service properties directly from theServiceReference
interface@Inject @Reference ServiceReference<Person> personReference;
-
Map<String, Object>
- the service properties inMap
form. Notice in this scenario that the reference must be qualified by a service type. (This can also be used in other scenarios to narrow the services obtained to a more specific type. However, except in the Map use case, this qualified type must be a subtype of the type specified in the reference.)@Inject @Reference(Person.class) Map<String, Object> personProperties;
-
Map.Entry<Map<String,Object>, S>
- aMan.Entry
holding the service properties map as key and the service instance as the value.@Inject @Reference Map.Entry<Map<String, Object>, Person> personAndProperties;
-
BeanServiceObjects<S>
- a special type mapping toServiceObjects
providing support for prototype scope services. Get the service properties via thegetServiceReference
method on this interface.@Inject @Reference BeanServiceObjects<Person> persons;
Making a reference optional is simply using the Optional
type around the service type.
@Inject
@Reference
Optional<Person> person;
// OR
@Inject
@Reference
Optional<Map.Entry<Map<String, Object>, Person>> person;
A reference can have multi-cardinality by specifying a container type of java.util.Collection<R>
, or java.util.List<R>
where R
is one of the types specified in the previous sections.
@Inject
@Reference
Collection<Person> persons;
// OR
@Inject
@Reference
List<Map.Entry<Map<String, Object>, Person>> persons;
Unless otherwise specified, the minimum cardinality is zero (0) making multi-cardinality references effectively optional by default.
@Inject
@Reference
List<Map.Entry<Map<String, Object>, Person>> persons; // min cardinality is 0, therefore this will resolve when no person services exist
In order to specify a minimum cardinality use the @MinimumCardinality
annotation on a multi-cardinality reference.
@Inject
@MinimumCardinality(3)
@Reference
List<Map.Entry<Map<String, Object>, Person>> persons;
Simply do not provide a minimum cardinality.
There are a number of ways to specify a target filter for references:
- specify a service filter in the
target
property on the@Reference
annotation. - specify any number of BeanPropertyTypes on the reference all of which will be AND'ed together in the order they are defined (after having been appended to any specified
target
value.)
@Inject
@Reference(target = "(&(foo=bar)(service.vendor=Acme, Ltd.))")
Collection<Dog> dogs;
// OR
@Inject
@Reference(target = "(foo=bar)")
@ServiceVendor("Acme, Ltd.")
Collection<Dog> dogs;
Both of the above produce the same target filter.
Tracking any and all service types in a reference is supported providing the following criteria are met:
@Reference.value
must specify the single valueReference.Any.class
.@Reference.target
must specify a valid, non-empty filter value.- The reference service type must be
java.lang.Object
.
@Inject
@Reference(value = Reference.Any.class, target = "(foo=bar)")
List<Map.Entry<Map<String, Object>, Object>> fooAreBars;
- add links on types throughout
- dynamic references
- portable extensions
- tooling on README