OSGi R7 Features
Here’s a brief rundown of new features added in OSGi R7 release (from core and compendium).
New Developers and SCM metadata headers:
Bundle-Developers: raymond.auge;email=raymond.auge@liferay.com;name="Raymond Augé"; organization="Liferay, Inc."
Bundle-SCM: url=https://github.com/liferay/foo,connection=scm:git:https://github.com/liferay/foo.git,developerConnection=scm:git:git@github.com:liferay/foo.git
Manifest Annotations build-time annotations designed to ease metadata maintenance
- Manifest Annotations
@Header @Headers
@Capability @Capabilities
@Requirement @Requirements
@Attribute @Directive
@Requirement.Resolution @Requirement.Cardinality
@Export @Export.Substitution
- Arbitrary headers
@Headers({ @Header(name = "X-FooHeader", value = "foo"), @Header(name = "X-FumHeader", value = "fum") }) public @interface MyHeaders {}
- User defined manifest header meta-annotations:
@Capability(namespace = "my.namespace") public @interface MyCapability { @Attribute("attr") String value(); }
@MyCapability("foo") public MyClass {}
101 Log Service
- Logging API: Logger, LoggerFactory, LogLevel
@Reference LoggerFactory loggerFactory; Logger logger = loggerFactory.getLogger(Bar.class); logger.error("Seems {} has erred", foo, exception);
- Streaming log handler: LogStreamProvider
@Reference LogStreamProvider logStreamProvider; logStreamProvider.createStream() .forEach(l -> System.out.println(l)) .onResolve(() -> System.out.println("stream closed"));
- Logging configuration: LoggerAdmin, LoggerContext: declarative and programmatic
configuration
@Reference LoggerAdmin loggerAdmin; loggerAdmin.getLoggerContext("com.foo.bar").setLogLevels(...);
- example configuration for PID
org.osgi.service.log.admin|com.foo.bar
:com.foo.bar.Impl=DEBUG
104 Configuration Admin Service
- Named factory instances, read-only, passive update, pre-processed configurations
Configuration c = configurationAdmin.getFactoryConfiguration( factoryPid, name, "?"); c.addAttributes(ConfigurationAttribute.READ_ONLY); c.updateIfDifferent(properties); Dictionary<String,Object> d = c.getProcessedProperties( ServiceReference<?> reference);
112 Declarative Services
- Activation/constructor injection
@Activate public Foo(@Reference Bar bar) {...} @Activate void activate(Config config, @Reference Bar bar) {...}
- Logger support
@Reference Logger logger;
- Factory properties
@Component( factoryProperties="OSGI-INF/factory.properties", factoryProperty="hours:Integer=24" )
- Detect change to runtime via
service.changecount
runtime service property@Reference(name = "src", updated = "set") void set(ServiceComponentRuntime scr){...}
- Component property types
@ComponentPropertyType public @interface Config { boolean enabled() default true; String[] names() default {"a", "b"}; } @Component @Config(names="myapp") @ServiceRanking(100) public class MyComponent { @Activate void activate(Config config) {...} }
Added support for JPA 2.1
- Standard configuration properties
- Updated configuration lifecycle rules
- New EntityManagerFactoryBuilder methods
String n = entityManagerFactoryBuilder .getPersistenceProviderName(); Bundle b = entityManagerFactoryBuilder .getPersistenceProviderBundle();
136 Resolver Service
- Define resolution of fragments
Collection<Resource> rs = resolveContext.findRelatedResources(resource);
- Define substitution wires
List<Wire> ws = resolveContext.getSubstitutionWires(wiring);
- Cancelable resolution callback
resolveContext.onCancel(() -> {/* do something */});
- Define dynamic resolving
resolver.resolveDynamic(resolveContext, wiring, requirement);
140 Http Whiteboard
- Standard Component property types
@Component( scope = ServiceScope.PROTOTYPE, service = Servlet.class) @HttpWhiteboardServletPattern("/as") class MyServlet extends HttpServlet {}
- Multipart support
@Component( scope = ServiceScope.PROTOTYPE, service = Servlet.class) @HttpWhiteboardServletPattern("/as") @HttpWhiteboardServletMultipart(maxFileSize = 10000) class MyServlet extends HttpServlet {}
- Servlet pre-processors, execute before security, filter chain
finishSecurity method
@Component @HttpWhiteboardTarget("(foo=bar)") class myPP implements Preprocessor {...} if (handleSecurity(req, res)) { try {/* do filter chain/servlet */ } finally { finishSecurity(req, res); } }
- Detect changes via
service.changecount
runtime service property@Reference(updated = "setHttpServiceRuntime", policy = DYNAMIC, policyOption = GREEDY) void setHttpServiceRuntime(HttpServiceRuntime hsr){ // has changed }
- HttpService integration
@Component( scope=ServiceScope.PROTOTYPE, service = Filter.class) @HttpWhiteboardFilterPattern("/*") @HttpWhiteboardContextSelect( "(osgi.http.whiteboard.context.httpservice=*)") public class MyFilter implements Filter {...}
147 Transaction Control Service NEW
- Portable, modular abstraction for Transaction lifecycle management
final TransactionControl tc; final Connection connection; @Activate public Messenger( @Reference TransactionControl tc, @Reference JDBCConnectionProvider provider) { this.tc = tc; this.connection = provider.getResrouce(control) } public void addMessage(String message) { tc.required(() -> { //start scope PreparedStatement ps = connection.prepareStatement( "Insert into MESSAGE values ( ? )"); ps.setString(1, message); return ps.executeUpdate(); }); // end scope }
- Allow different resource types to be easily used within a Transaction
- Exception handling
- Rollback avoidance
- Multithreading
- Associate resources with scope
- TX lifecycle callbacks
- Enlist resources with TX
- Mark TX for rollback
- Local & XA
- Builder pattern
- Resource providers
- etc.
148 Cluster Information NEW
API for a management agent to discover, list and inspect available nodes in the cluster.
- Property Prefix: osgi.clusterinfo.
- NodeStatus service properties:
Map<String, Object> m = nodeStatus.getMetrics(names);
- id
- cluster
- parent
- endpoint
- endpoint.private
- vendor
- version
- country
- location
- region
- zone
- tags
- FrameworkNodeStatus properties:
interface FrameworkNodeStatus extends FrameworkManager, NodeStatus {} BundleDTO bdto = frameworkNodeStatus.installBundle(location);
- org.osgi.framework.version
- org.osgi.framework.processor
- org.osgi.framework.os_name
- java.version
- java.runtime.version
- java.specification.version
- java.vm.version
150 Configurator NEW
Feed configurations into Configuration Admin through
- configuration resources, multiple PIDs, multiple
- configuration resources, extender pattern, UTF-8 encoded
- JSON resources, installed via bundles e.g.
OSGI-INF/configurator/foo.json
:{ // Global Settings ":configurator:resource-version" : 1, "pid.a": { "key": "val", "some_number": 123 }, "factory.pid.b~name": { "a_boolean": true } }
- Ranking, factory configs, typed, binary data, overwrite
{ "my.config": { "security.enabled": true, "public.key:binary" : "/OSGI-INF/files/mykey.pub" } }
- policy, well defined lifecycle, via system property, coordinator
-Dconfigurator.initial={"pid.a": {"some_number": 123}}
-Dconfigurator.initial=file:/some.json,file:/other.json
- integration, standalone configurations
151 JAX-RS Whiteboard NEW
- Register JAX-RS annotated POJO (resources), Applications,
- Extensions as services, simple collaboration model
@Component(service = Foo.class) @JaxrsName("foo") @JaxrsResource @Path("foo") class Foo { @GET @Path("{name}") public String interrogateSession( @PathParam("name") String name, @Context HttpServletRequest req) { HttpSession s = req.getSession(); return String.valueOf(s.getAttribute(name)); } }
- Require extensions, static resources, multiple whiteboards with own endpoints, simplified default applications,
@Component @JaxrsExtensionSelect("(osgi.jaxrs.name=configProvider)")
- Detect runtime changes via
service.changecount
runtime service property:@Reference(updated = "setJaxRSServiceRuntime", policy = DYNAMIC, policyOption = GREEDY) void setJaxRSServiceRuntime(JaxRSServiceRuntime runtime){ // has changed }
705 Promises
- Thrown exceptions in Function and Predicate, timeout/delay, specify executor/scheduledExecutor, support Callback from org.osgi.util.function
final Promise<String> answer = new Deferred<String>( executor, scheduledExecutor ).getPromise().delay(1000).timeout(5000).then( new Callback() { @Override public void run() throws Exception { System.out.println(answer); } } );
706 Push Stream NEW
- Compact pipeline asynchronous tasks on event arrival, circuit breaker, finite streams & back pressure explicit in API signatures, inspired by Java 8 Streams API, independent, generics, lazy, composed by functional steps, mapping, flat mapping, filtering, stateless & stateful intermediate operations
PushEventSource<Integer> source = ... Integer i = new PushStreamProvider().buildStream(source) .withPushbackPolicy(LINEAR, 20) .withQueuePolicy(FAIL) .build() .max(Integer::compare) .getValue().get();
707 Converter NEW
- Make it easy to convert many types to other types, scalars, collections, maps, beans, interfaces and DTOs, no boilerplate conversion code, customized using converter builders, generics, rules
Converter c = Converters.standardConverter(); MyEnum e = c.convert(MyOtherEnum.BLUE).to(MyEnum.class); BigDecimal bd = c.convert(12345).to(BigDecimal.class); long[] la = c.convert( Arrays.asList("978", "142")).to(long[].class); Map m = Collections.singletonMap("timeout", "700"); int t = c.convert(m).to(MyInterface.class).timeout(); Map m = Collections.singletonMap("args", null) String[] a1 = c.convert(m).to(MyAnnotation.class).args();