Tuesday, April 10, 2018

OSGi R7 Highlights: The Converter

One of the entirely new specifications in the OSGi R7 set of specs is the Converter specification. The converter can convert between many different Java types and can also be a highly convenient tool to give untyped data a proper API.

Let's dive in with some simple converter examples:

// Obtain the converter
Converter c = Converters.standardConverter();

// Simple scalar conversions
int i = c.convert("123").to(int.class);
UUID id = c.convert("067e6162-3b6f-4ae2-a171-2470b63dff00")
           .to(UUID.class);
BigDecimal bd = c.convert(12345).to(BigDecimal.class);

Collections, arrays and maps can also be converted:

List<String> ls = Arrays.asList("978", "142", "-99");

// Convert a List of Strings to a Set of Integers, 
// note the use of TypeReference to capture the generics
Set<Integer> is = c.convert(ls)
                   .to(new TypeReference<Set<Integer>>(){});

// Convert between map-like structures
Dictionary<String, String> d = ...; // some dictionary
Map m = c.convert(d).to(Map.class);

// Even though properties contain String keys and values, you 
// can't assign them to a Map<String, String>, the converter 
// can make this easy...
Properties p = ...; // a properties object
Map<String, String> n = c.convert(p)
           .to(new TypeReference<Map<String,String>>(){});

The above examples show that many different types of conversions can be made with the converter, using the same convert(object).to(type) API.

Note that the converter is obtained by calling Converters.standardConverter() so by default it's not registered in the service registry. This makes the converter usable in both OSGi Framework as well as in plain Java environments.

Backing Objects

An interesting feature of the converter is that it can convert between maps and Java types such as interfaces, annotations and java beans. Together we call these map-like types. In certain cases the conversion can provide a live view over the backing object. 

For example, let's say you have an interface MyAPI:

interface MyAPI {
    long timeout();
    long timeout(long defval);
}

Now you have a map that contains a timeout key with some value, if you want to expose that via the MyAPI interface the converter can do this:

Map<String, Long> m = new HashMap<>();
m.put("timeout", 999L);
MyAPI o = c.convert(m).to(MyAPI.class);
System.out.println(o.timeout()); // prints 999
m.put("timeout", 1000L);         // update the underlying map
System.out.println(o.timeout()); // prints 1000

The other way around is also possible. For example, if you have a JavaBean that you need to view as a Map, then the converter can do this. In the following example, we see that in order for the converter to handle a source object as a JavaBean you need to specify the sourceAsBean() modifier. Additionally, live views for maps are not enabled by default and are enabled with the view() modifier.

MyBean bean = new MyBean();
bean.setLength(120);
bean.setWidth(75);
Map<String, String> bm = c.convert(bean).sourceAsBean().view()
           .to(new TypeReference<Map<String,String>>(){});
System.out.println("Bean map:" + bm);
bean.setWidth(125)                    // update the bean
System.out.println("Bean map:" + bm); // map reflects the update

In addition to the map-like types mentioned above, the converter can handle DTOs and when an object exposes a method called getProperties(), it can take this as the source map as well.

Defaults

Converting a map or properties object to a Java interface can be a really useful way to give some untyped configuration a well-defined API. Often you'd want to be able to specify some defaults for the configuration values that you're using, in case they are not specified. When converting to interfaces or annotations defaults can be specified.

When converting to an interface, the interface may define a one-argument method to specify the default, as is done with the MyAPI interface above. To specify the default pass it into the method:

Map<String, Long> m = new HashMap<>(); // empty map
MyAPI o = c.convert(m).to(MyAPI.class);

// default to 750 if no timeout is in the map
System.out.println(o.timeout(750L));

Handling defaults via an annotation is even a little neater, as the Java annotation syntax allows for the specification of defaults.     

@interface MyAnn {
    long timeout() default 100;
}

MyAnn a = c.convert(m2).to(MyAnn.class);
System.out.println(a.timeout()); // use default 100
m2.put("timeout", 500L);
System.out.println(a.timeout()); // now get the actual value 500


Customizing Converters

While the converter can convert between many types (see the spec chapter for the actual list of supported types) it doesn't understand every single Java type ever created. Let's say we have two custom types Foo and Bar. There is a conversion between the two, but the converter doesn't know about it. We can create a customized converter that, on top of its existing conversions, knows about our special conversion as well!

Let's say our custom classes look a bit like this. The Foo class can be represented as a string which you can obtain via its read() method. The Bar class can hold a byte array.

public class Foo {
    // ...
    public String read() {
        return val;
    }
}

public static class Bar {
    byte[] buf;

    public static Bar create(byte[] b) {
        Bar bar = new Bar();
        bar.buf = b;
        return bar;
    }
}

To create a converter that, on top of the existing conversions, knows about Foo and Bar, we use a converter builder and register a rule with that to do the conversion. In the example below, the Rule object declares the source and the target of the rule. The conversion is provided as a lambda:

Foo f = ...; // Some Foo object
Converter custom = c.newConverterBuilder()
    .rule(new Rule<Foo, Bar>(
        foo -> Bar.create(foo.read().getBytes())){})
    .build();

// Now we can convert Foo to Bar!
Bar b = custom.convert(f).to(Bar.class);

Now the converter can convert our custom objects. An additional benefit is that the converter is an immutable object. You can customize an already customized converter by creating a new converter based on the previously created custom one.

Because the converter is immutable it's ideal for sharing, so once you've customized the perfect converter for your application, a good way to share it is by registering it in the OSGi Service Registry, and because the default converter isn't available in the service registry, your application components can simply look up the Converter service to get the one you registered for application wide usage.

Getting Started

This blog post doesn't cover all the details of the converter specification. See the spec chapter for more info on those. Like to get started straight away? At the time of this writing the specs are still under vote and not yet finally released. However, you can obtain a snapshot converter implementation from the OSGi Maven Repo: https://oss.sonatype.org/content/repositories/osgi/org/osgi/org.osgi.util.converter/ or you can build one yourself from the codebase in the Apache Felix project: https://svn.apache.org/repos/asf/felix/trunk/converter/converter.



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
  3. Declarative Services
  4. The JAX-RS Whiteboard
Be sure to follow us on Twitter or LinkedIn or subscribe to our Blog feed to find out when it's available.

An evening of OSGi with BGJUG on April 17 Sofia, Bulgaria

The BGJUG and Software AG are kindly hosting an Evening of OSGi on Tuesday April 17 from 7pm.

The OSGi Alliance is in Sofia conducting its Expert Group face to face meetings and Board meeting so this evening event will provide an excellent opportunity to meet with the local Java community while we are in town.

There are two talks lined up from the OSGi Alliance:

  • the first is an 'Introduction to OSGi' by BJ Hargrave (OSGi Alliance CTO) and 
  • the second is a look at 'How OSGi Alliance specifications have influenced the IoT market' by Pavlin Dobrev & Kai Hackbath (Bosch). 

In addition Todor Boev from Software AG will be presenting 'OSGi and JPMS in practice' which will discuss Software AG's experiences with OSGi and Jigsaw/JPMS now that Java 9 is released.

The event is being held at Sofia Tech Park / Incubator building, Tsarigradsko shoes 111B, 1784 Sofia [MAP].

Please be sure to register in advance to secure your place.

Thanks to BGJUG and Software AG for their assistance in arranging this event and of course to the speakers for their support.

We hope you can join us.

Tuesday, March 27, 2018

OSGi R7 Highlights: The JAX-RS Whiteboard

OSGi R7 is more than just an update to the existing OSGi specifications, it also includes a host of new specification chapters adding modularity to Java technologies. Today I want to tell you about about the exciting new support for RESTful services using the JAX-RS Whiteboard specification.

OSGi has long offered support for the web using Servlets, but these can be cumbersome for creating modern APIs which may need to represent data in a variety of ways. JAX-RS streamlines these sorts of applications by separating the routing of requests and serialization of entities from the business logic of your application.

JAX-RS: The Basics

A JAX-RS application uses resources to handle incoming requests. The method used to handle an incoming request is determined using annotations.
public class Upper {
  @Path("rest/upper/{param}")
  @GET
  public String toUpper(@PathParam("param") String param) {
    return param.toUpperCase();
  }
}

JAX-RS resources are then grouped together (along with extension services) in an Application which is hosted by the server runtime. This model is very similar to that used by Servlets in a WAR file, and so unsurprisingly the best way to use JAX-RS resources in an OSGi framework is very similar to the way you would use a Servlet!

The JAX-RS Whiteboard

When in an OSGi framework, we want our applications to be modular and loosely coupled. The best way to contribute a JAX-RS resource is therefore to register it as a service with the JAX-RS whiteboard. Using the new Declarative Services Component Property Types makes this really easy!

@Component(service=Upper.class)
@JaxrsResource
public class Upper {
    @Path("rest/upper/{param}")
    @GET
    public String toUpper(@PathParam("param") String param) {
        return param.toUpperCase();
    }
}

Note that JAX-RS doesn't impose any type restrictions on the resource object, so the whiteboard doesn't either. Any service registered with the "osgi.jaxrs.resource" property set to true (provided here by the @JaxrsResource component property type) will therefore be picked up by the whiteboard and used as a resource.

In addition to individual resources the whiteboard can also host entire JAX-RS Application instances:

@Component(service=Application.class)
@JaxrsApplicationBase("myApp")
public class MyApp extends Application {
    ...
}

These applications are isolated from one another, allowing multiple bundles to contribute RESTful APIs without fear of conflict.

Extending the JAX-RS Whiteboard

A key feature of the JAX-RS model is its extensibility. Support for new media types, content encodings, custom exception mapping and many other facilities are provided using extension types. These extension types are also supported by the JAX-RS whiteboard and can be registered just as easily as any other types!

@Component
@JaxrsExtension
@Produces("application/vnd.acme.foo")
public class MyExt implements MessageBodyReader,
                              MessageBodyWriter {
   ...
}

In summary

The JAX-RS whiteboard offers a powerful, flexible, easy-to-use model for creating RESTful APIs for your OSGi bundles. The Reference Implementation at Apache Aries is available now for you to try out, and there are examples for developing JAX-RS whiteboard applications at OSGi enRoute. More information (and a lot of additional features) are described in the R7 specification. Have Fun!


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
  3. Declarative Services
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.

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 27, 2018

OSGi R7 Highlights: Java 9 Support

With the Java 9 release, the Java Platform Module System (JPMS) is a major feature that impacts many areas of the Java Platform.  The JPMS is used to modularize the class libraries provided by the Java Platform.  In addition, it has been proposed that the JPMS can be used by developers to modularize their own applications, although the OSGi Alliance cautions against its use here.

Meanwhile the OSGi Core specification has provided a stable platform for developing modular Java applications for well over 17 years.  The OSGi Core R7 specification continues this tradition by providing updates to the OSGi Core specification which are fully compatible with previous versions of the OSGi Core specification.  OSGi Core R7 Framework implementations will be able to run on top of Java 9 without requiring any changes to existing OSGi application bundles (assuming no internal packages from the Java platform are being used).

The OSGi Core R7 specification has a couple of new features that build upon some features new to Java 9.  This includes support for multi-release JARs and runtime discovery of packages provided by the JPMS modules loaded by the platform.  First I will tell you about the multi-release JAR support.

Multi-Release JAR Support

Java 9 introduces a new type of JAR called a multi-release JAR.  A multi-release JAR file allows for a single JAR to support multiple major versions of the Java platform. For example, a multi-release JAR file can depend on both the Java 8 and Java 9 major platform releases, where some class depend on APIs in Java 8 and other class depend on APIs in Java 9.

The purpose of multi-release JARs is to support alternative implementation of select classes to deal with changes in the visible APIs of the Java platform.  That is, it is not meant as a means to supply new function or new API on different Java platform versions. As a best practice new APIs should be released in an updated version of an existing bundle or released as part of a new bundle.

The OSGi Core R7 specification adds support for multi-release JAR files. An OSGi bundle file can be a multi-release JAR by adding the following manifest header to the bundle manifest:

 Multi-Release: true

Any JAR included on the bundle class path can also be independently declared as a multi-release JAR by including the same manifest header:

  Multi-Release: true

in its own JAR manifest. For example, an OSGi bundle can include third-party multi-release JARs on its own bundle classpath. In this case the third-party multi-release JARs will be loaded as multi-release JARs by the OSGi Framework even if the bundle JAR itself is not a multi-release JAR.

When a JAR on the bundle class path is a multi-release JAR, then the Framework must search the JAR's versioned directories when attempting to locate a class or resource in the JAR. For more information on how classes and resources are loaded from multi-release JARs see the multi-release JAR documentation.

Different implementations of a Java class for different versions of the Java platform can affect the requirements of the bundle.  For example, what packages need to be imported from the running Java platform. The R7 Framework supports supplemental manifest files that can be used to specify alternative values for the Import-Package and Require-Capability manifest headers for different versions of the Java platform.

When a bundle file is a multi-release JAR, then the Framework must also look for a supplemental manifest file, OSGI-INF/MANIFEST.MF, in the versioned directories. For example:

  META-INF/versions/9/OSGI-INF/MANIFEST.MF

The Framework finds the highest versioned manifest available in the multi-release JAR which can be applied to the running Java platform and uses the Import-Package and Require-Capability manifest headers as replacements for the values specified in the bundle's manifest.

The purpose of the supplemental manifest is to specify requirements on capabilities provided by different versions of the Java platform which are needed by the implementation classes for that Java platform version. As a best practice, the supplemental manifests should not contain additional requirements on capabilities which are not supplied by the Java platform for the Java version associated with the supplemental manifest.

For more information about multi-release JAR support you can refer to the following sections of the OSGi Core R7 specification:
  1. Bundle File Multi-release JAR
  2. Bundle class path Multi-release Container

Runtime Discovery of Java Platform Packages

Now that the Java platform is modularized in Java 9, the runtime can be configured to load only the modules which are required by the application.  This allows for a smaller custom runtime that is tailored to the needs of a specific application.  The set of java.* packages provide by the running Java platform is no longer constant for a specific version of the Java platform.

Bundles typically depend on different packages by using requirements specified with the Import-Package header, but as of the OSGi Core R4 specification, bundles have been prohibited from using Import-Package to specify requirements on java.* packages.  Instead bundles have used the osgi.ee namespace (or the deprecated Bundle-RequiredExecutionEnvironment header) to specify a dependency on specific versions of the Java platform. It has been assumed that the set of java.* packages available for a specific version of the Java platform is constant and therefore there is no need to specify additional requirements on specific java.* packages.

With Java 9 this is no longer a valid assumption.  With OSGi Core R7, the osgi.ee namespace should only be used to specify the minimal level of the Java platform required by the Java class bytecode level included in the bundle.  Dependencies on specific java.* packages should to be specified using the Import-Package header.

The OSGi Core R7 specification now allows bundles to use the Import-Package header to import java.* packages.  The OSGi Framework implementation is required to discover the all available java.* packages in the running Java platform and automatically provide the java.* package as a separate system packages (see the system packages configuration property).  The system bundle is the only bundle that is allowed to provide java.* packages. It is an error for normal bundles to attempt to export java.* packages using the Export-Package header.

When importing java.* packages only the package name should be specified, no other matching attributes are needed.  For example:

  Import-Package: java.sql

Note that bundle class loaders in R7 continue to have full visibility to all available java.* packages available in the running Java platform.  The class and resource loads for the java.* packages will continue to be boot delegated by the framework implementation even when the bundle does not specify any Import-Package header. The java.* package requirements are only necessary to prevent a bundle from resolving if the necessary java.* packages are not available at runtime.  For example, if a bundle must only resolve if the java.sql module is loaded.

For more information about java* package support you can refer to the following sections of the OSGi Core R7 specification:
  1. Execution Environment
  2. Parent Delegation 

Bundles Supporting R6 and R7 Frameworks

The OSGi Core R6 specification prohibits bundles from importing java.* packages and will throw a BundleException if such a bundle is attempted to be installed. Bundles that must work on OSGi R6 and earlier Frameworks but also want to run on R7 Frameworks have two options:

  1. Do not import the java.* packages.  The bundle will continue to work on an R7 framework because java.* packages are still boot delegated by the bundle class loaders. This implies the bundle may resolve when running on Java 9 even when all the java.* packages required by the bundle are not available.
  2. Package the bundle as a multi-release JAR to allow alternative values for Import-Package to be specified.
A bundle that must still be able to be installed on an OSGi R6 or earlier Framework must not specify java.* packages in their main bundle manifest Import-Package header. A supplemental manifest must also be included to be able to specify java.* package imports.

This supplemental manifest must contain the original Import-Package header from the main bundle manifest as well as any java.* package required by the bundle. When running on an OSGi R6 Framework, this supplemental manifest will be ignored and therefore the bundle will install successfully as the bundle did not specify an import for the java.* packages in the main manifest.

If a bundle will always require OSGi R7 or greater Framework, there is no need to use multi-release JARs for this purpose even when the bundle must support Java 8 or earlier. This is because OSGi R7 frameworks must provide the java.* package capabilities on all Java platform versions the framework implementation supports. As long as the java.* package is available on the running Java platform, the bundle with an import for the java.* package must resolve.

I advise using option 1 here because it is by far the most simple approach.  If you really have a strong need to use this new R7 feature then I recommend you do not try to produce a single bundle version that supports both R6 and R7 Frameworks.  Instead simply release a new version of your bundle that only supports OSGi R7 or greater Frameworks.

In Summary

The OSGi Core R7 release continues the tradition by providing a stable modular platform with updates to the OSGi Core specification which are fully compatible with previous versions of the OSGi Core specification.  OSGi bundle developers can continue to develop advanced modular applications and run their applications on Java 9 without having to commit to migrating to the green initial release of JPMS.

The OSGi Core R7 specification does add new functionality in support of new features available in Java 9, such as the support for multi-release JARs and importing of java.* packages.  The OSGi specifications will continue to evolve in order to provide the necessary tools for developing advanced modular applications.

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 provide 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!

Wednesday, January 17, 2018

OSGi Community Event Slides and Videos

I can't believe we are already into the third week of 2018 and the holidays and year-end festivities are long forgotten already.  That is of course unless you celebrate Chinese New Year, which is only a month away now.

The presentations and video recordings from the OSGi Community Event 2017 conference are now available. These can be found on the OSGi Community Event 2017 home page

Unfortunately, for the first time in at least 5 years, I was not able to make it to the event last year. I hear from all accounts though that it was another successful co-location with EclipseCon Europe. We had a packed tutorial on OSGi and Bndtools, some excellent presentations, and an engaging and lively Birds of a Feather session. 

It was also great to have Intel delivering the OSGi Keynote discussing their experiences and key learnings from modularizing one of their applications by migrating to OSGi (Slides / Video).

New for the 2017 event, we have created a YouTube playlist of all of the presentations from the conference. So if you have some time and just want to kick back and watch lots of videos on OSGi be sure to check this out. 

We have also created video playlists for the 2015 and 2016 OSGi Community Events too and you can find all of these on the OSGi Alliance YouTube Channel.

2018 looks set to be a very busy year for the OSGi Alliance with the R7 (Release 7) specification due and several new opportunities for you to tell us and the world about how you are using OSGi whether you are an individual, a small, medium or large end user, or a software vendor.

We are always interested in your feedback and suggestions so if you have anything you want to share or suggest you can add it is a comment to this post or send it to the OSGi Marketing team.

That just leaves me to wish everyone the best for 2018 and encourage you to stay tuned to this blog, our Twitter feed and/or join our LinkedIn Group to hear the latest news and be notified about the technical posts on modularity coming up this year.

Blog Archive