Showing posts with label declarative services. Show all posts
Showing posts with label declarative services. Show all posts

Wednesday, March 14, 2018

OSGi R7 Highlights: Declarative Services

The OSGi Compendium Release 7 specification contains version 1.4 of the Declarative Services specification which includes a number of exciting new features.

If you are not familiar with Declarative Services (DS), it is the dependency injection model for OSGi programming that fully supports OSGi modularity and services and the dynamic nature of both. Declarative Services uses a declarative model for publishing, finding and binding to OSGi services. This model simplifies the task of authoring OSGi services by performing the work of registering the service and handling service dependencies. This minimizes the amount of code a programmer has to write; it also allows service components to be loaded only when they are needed. As a result, bundles need not provide a BundleActivator class to collaborate with others through the service registry.

Declarative Services was introduced as an OSGi specification in 2005 supporting method injection. DS has been updated to add an annotation-based programming model in version 1.2 and to add support for field injection,  component property types, and introspection in version 1.3. Version 1.4 of DS now adds support for constructor injection, activation fields, enhancements to component property types, and a number of smaller enhancements.

Service Component


A Service Component is a Java class which can be optionally registered as an OSGi service and can optionally use OSGi services. The runtime for DS is called Service Component Runtime (SCR) and uses component descriptions in the bundle (in XML form) to instantiate and wire components and services together. The component descriptions are used by SCR as a performance choice so that SCR can avoid processing all classes in a bundle to search for annotations at runtime. But writing XML is not really great for developers, so DS provides annotations which can be used in source code. Tooling, such as Bnd, is then used to generate the component description XML from the annotations during bundle building. So when the following example service component is included in a bundle by Bnd, Bnd will process the annotations and generate the component description XML for the component in the bundle.

@Component
public class ExampleImpl implements Example {
 @Reference(service=LoggerFactory.class)
 private Logger logger;
 @Override
 public void say(String message) {
  logger.info(message);
 }
}

<scr:component name="example.provider.ExampleImpl"
  xmlns:scr="http://www.osgi.org/xmlns/scr/v1.3.0">
  <implementation class="example.provider.ExampleImpl"/>
  <service>
    <provide interface="example.api.Example"/>
  </service>
  <reference field="logger"
    interface="org.osgi.service.log.LoggerFactory"
    name="Logger"/>
</scr:component>

Constructor Injection


Prior to 1.4, DS supported method injection:

private Example example;
@Reference
void setExample(Example example) {
 this.example = example;
}

and field injection:

@Reference
private Example example;

New to DS 1.4 is support for constructor injection:

private final Example example;
@Activate
public ExampleImpl(@Reference Example example) {
 this.example = example;
}

The Activate annotation is used to mark the constructor to be used by SCR for constructor injection. By default, SCR will use the public no-parameter constructor. Since, by their nature, constructors can only be called once per object instance, only static policy references can be used for constructor injection. For dynamic policy references, you will need to use either field or method injection.

Both scalar and multiple cardinality references are supported for constructor injection. Here is an example of multiple cardinality where the type of the referenced service is determined from the generic signature of the parameter.

private final List<Example> examples;
@Activate
public ExampleImpl(@Reference List<Example> examples) {
 this.examples = examples;
}

In addition to injecting the service objects for referenced services, you can also inject objects related to referenced services just as you can also do for method and field injection.

@Activate
public ExampleImpl(
  @Reference
  ServiceReference<Example> sr,
  @Reference
  ComponentServiceObjects<Example> so,
  @Reference(service=Example.class)
  Map<String,Object> serviceProps,
  @Reference
  Map.Entry<Map<String,Object>,Example> tuple) {
    …
}

Finally, constructor injection also supports passing activation objects to the component constructor. Activation objects are the objects you can pass to the activate method. Any constructor parameter not annotated with Reference must be an activation object.

public @interface Props {
 int my_port() default 8080;
}
@Activate
public ExampleImpl(
  ComponentContext context,
  BundleContext bc,
  Map<String,Object> componentProps,
  Props props) {
    …
}

Activation Fields


In addition to supporting injecting activation objects using constructor injection, and also method injection via the activate method, DS 1.4 adds support for field injection of activation objects. A field of the type of an activation object can be annotated with Activate and SCR will inject the activation object into the field after object construction.

@Activate
private ComponentContext context;
@Activate
private BundleContext bc;
@Activate
private Map<String,Object> componentProps;
@Activate
private Props props;

Component Property Type Enhancements


Component property types were added to DS in version 1.3. A component property type is an annotation that is used to both define and consume component properties in a type safe manner. For example, we can define the following component property type:

public @interface Props {
 int my_port() default 8080;
}

When this component property type is used in a component:

@Activate
private Props props;

it both defines the component property named my.port (the annotation element names are mapped to component property names) and sets its value to 8080 in the generated component description. SCR will also generate an instance of the component property type which can be injected into the component instance and then be used to access the component property in a type safe manner.

int my_port = props.my_port();

And since DS supports type conversion for the component property value, even if the component property value was a string value of "8080", your component implementation does not need to worry.

Lets say you wanted to set the my.port component property for your component to a value other than 8080 and could not change the declaration of the component property type (because other components might also use the same component property type), in DS 1.3 you would have to use a non-type-safe string:

@Component(property={"my.port:Integer=9080"})

New for DS 1.4 is the ability to also use component property types to annotate components and set property values in a type-safe manner. To use a component property type in this way, you must annotate the component property type with ComponentPropertyType. This meta-annotation lets Bnd know the annotation on the component class must be processed as a component property type for setting component property values.

@ComponentPropertyType
public @interface Props {
 int my_port() default 8080;
}
@Component
@Props(my_port=9080)
public class ExampleImpl implements Example {
  @Activate
  private Props props;
  …
}

Now when Bnd processes the component during bundle creation, the generated component description will set the value of the my.port component property to 9080.

There is also special support for component property types which are single-element annotations and marker annotations. For a single-element annotation, the component property name for the value element is derived from the component property type name instead of the element name value. For a marker annotation, a component property name is derived from the component property type name, just as for single-element annotations, and the component property value is Boolean.TRUE. Marker annotations are only useful for setting a component property to the value true. They cannot be used to get a property value since they have no elements to call from your component implementation.

Sometimes component property names can be long. For example, osgi.http.whiteboard.servlet.name. In order to make using component property types more friendly in source code, DS supports the use of the PREFIX_ final field so that shorter element names can be mapped to longer component property names. For example, if we need the component property name com.acme.server.port and we don't want to name the element com_acme_server_port or name the single-element annotation ComAcmeServerPort, we can use the PREFIX_ final field to add a name prefix to the mapped component property name.

@ComponentPropertyType
public @interface ServerPort {
  String PREFIX_ = "com.acme."; 
  int value() default 8080; // com.acme.server.port property
}

This new support for component property types is so useful, you will see we have defined quite a number of them throughout many of the R7 specifications to make using those specifications with DS much nicer. The DS spec defines some component property types for basic service properties and both the updated Http Whiteboard and the new JAX-RS Whiteboard specifications define component property types specific to their specifications.

And There is More


I just touched on, what I feel, are the major updates for Declarative Services in the new version 1.4 specification which is part of OSGi Compendium Release 7. Make sure to check out the Changes section in the spec to see all the updates for 1.4.

PS. While the DS 1.4 specification is done, tooling and runtimes which support all of these new features may still be under development (at the time of this writing).



Want to find out more about OSGi R7?

This is one post in a series of 12 focused on OSGi R7 Highlights.  Previous posts are:

  1. Proposed Final Draft Now Available
  2. Java 9 Support
Coming up next is The JAX-RS Whiteboard.  Be sure to follow us on Twitter or LinkedIn or subscribe to our Blog feed to find out when its available.

Tuesday, February 13, 2018

OSGi R7 Highlights: Proposed Final Draft Now Available

I am pleased to announce that the OSGi Alliance has published the Proposed Final Drafts of the OSGi Core R7 and Compendium R7 specifications. We expect that the final versions of these specifications will be published in April 2018 after OSGi Alliance member approval.

The R7 release builds upon the long history of the OSGi Alliance’s leadership in Java modularity and reflects a significant amount of effort from the technical members of the OSGi Alliance expert groups over the last 2 years. Thanks go to all of the members who have contributed to this release.

R7 represents many significant new features and capabilities and provides an open standards-based approach for a number of modern valuable and simple-to-use technologies important to Java developers.

This blog post is the start of a series of blog posts from the technical experts at the OSGi Alliance to share some of the key highlights of R7. The blog posts in this series will come out over the coming weeks and cover the following topics:
  • Java 9 Support – Multi-release JAR support and runtime discovery of the packages provided by the JPMS modules loaded by the platform.
  • Declarative Services – Constructor injection and component property types.
  • JAX-RS – A whiteboard model for building JAX-RS microservices.
  • Converter – A package for object type conversion.
  • Cluster Information – Support for using OSGi frameworks in clustered environments.
  • Transaction Control – An OSGi model for transaction life cycle management.
  • Http Whiteboard – Updates to the Http Whiteboard model.
  • Push Streams and Promises – The Promises packages is updated with new methods and an improved implementation and the new Push Streams package provides a stream programming model for asynchronously arriving events.
  • Configurator and Configuration Admin – Configuration Admin is updated to support the new Configurator specification for delivering configuration data in bundles.
  • LogService – A new logging API is added which supports logging levels and dynamic logging administration and a new Push Stream-based means of receiving log entries is also added.
  • Bundle Annotations – Annotations that allow the developer to inform tooling on how to build bundles.
  • CDI – Context and Dependency Injection support for OSGi developers.
Stay tuned and I hope you find the technical information in the blog post series useful to you as developers!

Friday, July 13, 2012

New RFPs available for feedback

Over the past while we have started making RFPs available at OSGi for public comments before they are finalized and voted on. This has worked really well for the OSGi Cloud RFP and the OSGi/CDI integration RFP.

Four new RFPs have been made available as part of this process. The RFPs describe uses cases and requirements which will ultimately feed into RFC work that will be the basis of future OSGi specifications.

RFP 143 OSGi Connect
The people at PojoSR have done some great work in showing how you can use OSGi Services in cases where you may not want to take on OSGi modularity (yet). RFP 143 captures requirements for creating a specification around this. The RFP can be found here: RFP 143.

RFP 150 HTTP Service Updates
The OSGi HTTP Service is widely used and it provides a very nice programming model for sevlets in an OSGi environment. However the specification is in need for an update to modernize it in relation to the Servlet spec itself. Additionally, the whiteboard pattern is introduced for servlet. You can find the RFP here: RFP 150.

RFP 151 Declarative Service Updates
A variety of updates are proposed to the Declarative Services specification. They can be found in RFP 151.

RFP 152 EJB Integration
EJB integration with OSGi has been done at Apache Aries and Glassfish. Other appservers such as JBoss and others also provide some form of interaction between EJBs and OSGi. This RFP aims a writing a specification for this integration to make OSGi-enabled EJBs portable. You can find the RFP here: RFP 152.

If you have thoughts or opinions about the above topic, have a read of the RFPs and put your comments on the associated bugs.