138 Asynchronous Service Specification

138.1 Introduction

OSGi Bundles collaborate using loosely coupled services registered in the OSGi service registry. This is a powerful and flexible model, and allows for the dynamic replacement of services at runtime. OSGi services are therefore a very common interaction pattern within OSGi.

As with most Java APIs and Objects, OSGi services are primarily synchronous in operation. This has several benefits; synchronous APIs are typically easier to write and to use than asynchronous ones; synchronous APIs provide immediate feedback; synchronous implementations typically have a less complex threading model.

Asynchronous APIs, however, have different advantages. Asynchronous APIs can reduce bottlenecks by encouraging more effective use of parallelism, improving the responsiveness of the application. In many cases high throughput systems can be written more simply and elegantly using asynchronous programming techniques.

The Promises Specification provides powerful primitives for asynchronous programming, including the ability to compose flows in a functional style. There are, however, many existing services that do not use the Promise API. The purpose of the Asynchronous Service is to bridge the gap between these existing, primarily synchronous, services in the OSGi service registry, and asynchronous programming. The Asynchronous Service therefore provides a way to invoke arbitrary OSGi services asynchronously, providing results and failure notifications through the Promise API.

138.1.1 Essentials

  • Async Invocation - A single method call that is to be executed without blocking the requesting thread.

  • Client - Application code that wishes to invoke one or more OSGi services asynchronously.

  • Async Service - The OSGi service representing the Asynchronous Services implementation. Used by the Client to make one or more Async Invocations.

  • Async Mediator - A mediator object created by the Async Service which represents the target service. Used by the Client to register Async Invocations.

  • Success Callback - A callback made when an Async Invocation completes with a normal return value.

  • Failure Callback - A callback made when an Async Invocation completes with an exception.

138.1.2 Entities

  • Async Service - A service that can create Async Mediators and run Async Invocations.

  • Target Service - A service that is to be called asynchronously by the Client.

  • Client - The code that makes Async Invocations using the Async Service

  • Promise - A promise, representing the result of the Async Invocation.

Figure 138.1 Class and Service overview

Class and Service overview

138.2 Usage

This section is an introduction in the usage of the Async Service. It is not the formal specification, the normative part starts at Async Service. This section leaves out some of the details for clarity.

138.2.1 Synopsis

The Async Service provides a mechanism for a client to asynchronously invoke methods on a target service. The service may be aware of the asynchronous nature of the call and actively participate in it, or be unaware and execute normally. In either case the client's thread will not block, and will continue executing its next instructions. Clients are notified of the completion of their task, and whether it was successful or not, through the use of the Promise API.

Each async invocation is registered by the client making a method call on an Async Mediator, and then started by making a call to the Async Service that created the mediator. This call returns a Promise that will eventually be resolved with the return value from the async invocation.

An Async Mediator can be created by the client, either from an Object, or directly from a Service Reference. Using a service reference has the advantage that the mediator will track the underlying service. This means that if the service is unregistered before the asynchronous call begins then the Promise will resolve with a failure, rather than continuing using an invalid service object.

138.2.2 Making Async Invocations

The general pattern for a client is to obtain the Async Service, and a service reference for the target service. The client then creates an Async Mediator for the target service, invokes a method on the mediator, then starts the asynchronous call. This is demonstrated in the following example:


      
private Async asyncService;
private ServiceReference<Foo> fooRef;
private Foo mediated;

@Reference
void setAsync(Async async) {
    asyncService = async;
}

@Reference(service = Foo.class)
void setList(ServiceReference<Foo> foo) {
    fooRef = foo;
}

@Activate
void start() {
    mediated = asyncService.mediate(fooRef, Foo.class);
}

public synchronized void doStuff() {
    Promise<Boolean> promise = asyncService
           .call(mediated.booleanMethod(“aValue”));
    ...
}

      

This example demonstrates how simply clients can make asynchronous calls using the Async Service. The eventual result can be obtained from the promise using one of the relevant callbacks.

One important thing to note is that whilst the call to call() or call(R) causes the async invocation to begin, the actual execution of the underlying task may be queued until a thread is available to run it. If the service has been unregistered before the execution actually begins then the promise will be resolved with a Service Exception. The type of the Service Exception will be ASYNC_ERROR.

138.2.3 Async Invocations of Void Methods

The return value of the mediator method call is used to provide type information to the Async Service. This, however, does not work for void methods that have no return value. In this case the client can either pass an arbitrary object to the call(R) method, or use the zero argument call() method. In either case the returned promise will eventually resolve with a value of null. This is demonstrated in the following example.


private Async asyncService;
private ServiceReference<Foo> fooRef;
private Foo mediated;

@Reference
void setAsync(Async async) {
    asyncService = async;
}

@Reference(service = Foo.class)
void setList(ServiceReference<Foo> foo) {
    fooRef = foo;
}

@Activate
void start() {
    mediated = asyncService.mediate(fooRef, Foo.class);
}

public synchronized void doStuff() {
    mediated.voidMethod();
    Promise<?> promise = asyncService
           .call();
    ...
}

138.2.4 Fire and Forget Calls

Sometimes a client does not require any notification that an async invocation has completed. In this case the client could use one of the call() or call(R) methods and simply discard the returned Promise object. This, however, can be wasteful of resources. The act of resolving the Promise object may be expensive, for example it may involve serializing the return value over a network if the remote call was asynchronous.

If the client knows that no Promise object representing the result of the asynchronous task is needed then it can signal this to the Async Service. This allows the Async Service to better optimize the async invocation by not providing a result.

To indicate that the client wants to make a fire-and-forget style call the client invokes the mediator as normal, but then begins the asynchronous invocation using the execute() method as show below.


private Async asyncService;
private ServiceReference<Foo> fooRef;

private Foo mediated;

@Reference
void setAsync(Async async) {
    asyncService = async;
}

@Reference(service = Foo.class)
void setList(ServiceReference<Foo> foo) {
    fooRef = foo;
}

@Activate
void start() {
    mediated = asyncService.mediate(fooRef, Foo.class);
}

public synchronized void doStuff() {
    mediated.someMethod();
    asyncService.execute();
    ...
}

Note that the execute() method does still return a Promise. This Promise is not the same as the ones returned by call() or call(R), its resolution value does not provide access to the result, but instead indicates whether the fire-and-forget call could be successfully started. If there is a failure which prevents the task from being executed then this is used to fail the returned promise.

138.2.5 Multi Threading

By their very definition asynchronous tasks do not run inline, and typically they will not run on the same thread as the caller. This is not, however, a guarantee. A valid implementation of the Async Service may have only one worker thread, which may be the thread currently running in the client code. Async invocations also have the same threading model as the Promise API. This means that callbacks may run on arbitrary threads, which may, or may not, be the same as the client thread, or the thread which executed the asynchronous work.

It is important for multi-threaded clients to note that calls to the mediator and Async Service must occur on the same thread. For example it is not supported to invoke a mediator using one thread, and then to begin the async invocation by calling the call(), call(R) or execute() method on a different thread.

138.3 Async Service

The Async Service is the primary interaction point between a client and the Async Service implementation. An Async Service implementation must expose a service implementing the Async interface. Clients obtain an instance of the Async Service using the normal OSGi service registry mechanisms, either directly using the OSGi framework API, or using dependency injection.

The Async Service is used to:

  • Create async mediators

  • Begin async invocations

  • Obtain Promise objects representing the result of the async invocation

138.3.1 Using the Async Service

The first action that a client wishing to make an async invocation must take is to create an async mediator using one of the mediate methods. Once created the client invokes the method that should be run asynchronously, supplying the arguments that should be used. This call records the invocation, but does not start the asynchronous task. The asynchronous task begins when the client invokes one of the call or execute methods on the Async Service. The call methods must return a Promise representing the async invocation. The promise must resolve with the value returned by the async invocation, or fail with the failure thrown by the async invocation.

If the client attempts to begin an async invocation without first having called a method on the mediator object then the Async Service must detect this usage error and throw an IllegalStateException to the client. This applies to all methods that begin an async invocation.

138.3.2 Asynchronous Failures

There are a variety of reasons that async invocations may be started correctly by the client, but then fail without running the asynchronous task. In any of these cases the Promise representing the async invocation must fail with a Service Exception. This Service Exception must be initialized with a type of ASYNC_ERROR. If there is no promise representing the async invocation then there is no way to notify the client of the failure, therefore the Service Exception must be logged by the Async Service using all available Log Service implementations.

The following list of scenarios is not exhaustive, but indicates failure scenarios that must result in a Service Exception with a type of async

  • If the client is using a service reference backed mediator and the client bundle's bundle context becomes invalid before looking up the target service.

  • If the client is using a service reference backed mediator and the service is unregistered before making the async invocation.

  • If the client is using a service reference backed mediator and the service lookup returns null

  • If the Async Service is unable to accept new work, for example it is in the process of being shut down.

  • If the type of the mediator object does not match the type of the service object to be invoked.

138.3.3 Thread Safety and Instance Sharing

Implementations of the Async Service must be thread safe and may be used simultaneously across multiple clients and from multiple threads within the same client. Whilst the Async Service is able to be used across multiple threads, if a client wishes to make an async invocation then the call to the mediator and the call to begin the async invocation must occur on the same thread. The returned Promise may then be shared between threads if required.

It is expected, although not required, that the Async Service implementation will use a Service Factory to create customized implementations for each client bundle. This simplifies the tracking of the relevant client bundle context to use when performing service lookups on the client bundle's behalf. Clients should therefore not share instances of the Async Service with other bundles. Instead both bundles should obtain their own instances from the service registry.

138.3.4 Service Object Lifecycle Management

If the Async Service is being used to call an OSGi service object and the service reference is available then the service object should be looked up immediately before the asynchronous task begins executing. This ensures that the service is still available at the point it is eventually called. Any call to getService must have a corresponding call to ungetService after the mediated method invoked has returned and, if available, the promise is resolved, but before the asynchronous task releases its thread of execution.

138.4 The Async Mediator

Async mediators are dynamically created objects that have the same type or interface as the object being mediated, and are used to record method invocations and arguments. Mediator objects are specific to an Async Service implementation, and must only be used in conjunction with the Async Service object that they were created by.

Mediators may be created either from a ServiceReference or from a service object. The actions and overall result are similar for both the mediate(ServiceReference,Class) and mediate(T,Class) methods, with the primary difference being that mediated objects created from a ServiceReference will validate whether the service object is still available immediately before the asynchronous task is executed.

138.4.1 Building the Mediator Object

The client passes in a Class indicating the type that should be mediated. If the class object represents an interface type then the generated mediator object must implement that interface. If the class object represents a Java class type then the mediator object must either be an instance of that type or extend it.

When building a mediator object the Async Service has the opportunity to detect numerous problems, for example if the referenced service to be mediated has been unregistered. Although fail-fast behavior is usually preferable, in this case it would force the client to handle errors in two places; both when creating the mediator, and for the returned Promise. To simplify client usage, error cases detected when creating a mediator must not prevent the mediator from being created and must not result in an exception being thrown. The only reason that the Async Service may fail to create a mediator is if the class object passed in cannot be mediated.

There are three reasons why the Async Service may not be able to mediate a class type:

  • The class object passed in represents a final type.

  • The class object passed in represents a type that has no zero-argument constructor.

  • The class object passed in represents a type which has one or more public final methods present in its type hierarchy (other than those declared by java.lang.Object).

If any of these constraints are violated and prevent the Async Service from creating a mediator then the Async Service must throw an IllegalArgumentException.

138.4.2 Async Mediator Behaviors

When invoked, the Async mediator must record the method call, and its arguments, and then return rapidly and should avoid performing blocking operations. The values returned by the mediator object are opaque, and the client should not attempt to interpret the returned value. The value may be null (or null-like in the case of primitives) or contain implementation specific information. If the mediated method call has a return type, specifically it is non-void, then this object must be passed to the Async Service's call method when beginning the async invocation

Async mediators should make a best-effort attempt to detect incorrect API usage from the client. If this incorrect usage is detected then the mediator object must throw an IllegalStateException when invoked. An example of incorrect usage that must be detected is when a client makes multiple invocations on a single mediator object from the same thread without making any calls to the Async Service.

After a usage error has been detected and an IllegalStateException has been thrown the mediator object must be reset so that a subsequent invocation from the client thread can proceed normally.

138.4.3 Thread Safety and Instance Sharing

Async mediators, like instances of the Async Service, are required to be thread safe. Clients may therefore share mediator objects across threads, and can safely store them as instance fields. Whilst mediators are thread safe, if a client wishes to make an async invocation then the call to the mediator and the call to call() or call(R) must occur on the same thread. The returned Promise may then be shared between threads if required.

Async mediators created from ServiceReference objects remain directly associated with the service reference and client bundle after creation. Clients should therefore not share mediator objects with other bundles. Instead each bundle should create its own mediator.

138.5 Fire and Forget Invocations

The Async Service provides call() and call(R) methods for clients to use when they wish to receive results from asynchronous tasks. Clients that do not need the result can simply discard the returned Promise object. This, however, can be wasteful of resources. The act of resolving the Promise object may be expensive, for example it may involve serializing the return value over a network.

To address this use case the Async Service provides the execute() method, which behaves similarly to call() and call(R), but does not provide access to the eventual result. Instead the execute() method returns a Promise that indicates whether the fire-and-forget call is able to be successfully started.

The returned Promise must be resolved with null if the asynchronous task begins executing successfully. There is no happens-before relationship required, meaning that if the Promise resolves successfully then the task may, or may not, have started or finished. The primary usage of the Promise is actually to detect failures. If the fire-and-forget task cannot be executed for some reason, for example the backing service has been unregistered, then the returned promise must be failed appropriately using the same rules as defined in Asynchronous Failures. If the returned Promise is failed then the fire-and-forget task has not executed and will not execute in the future.

138.6 Delegating to Asynchronous Implementations

Some service APIs are already asynchronous in operation, and others are partly asynchronous, in that some methods run asynchronously and others do not. There are also services which have a synchronous API, but could run asynchronously because they are a proxy to another service. A good example of this kind of service is a remote service. Remote services are local views of a remote endpoint, and depending upon the implementation of the endpoint it may be possible to make the remote call asynchronously, optimizing the thread usage of any local asynchronous call.

Services that already have some level of asynchronous support may advertise this to clients and to the Async Service by having their service object be an instanceof AsyncDelegate. The service object can be cast to AsyncDelegate to be used by the Async Service implementation, or by the client directly, to make an asynchronous call on the service.

Because the Async Delegate behavior is transparently handled by the Async Service, clients of the Async Service do not need to know whether the service object is an instanceof AsyncDelegate or not. Their usage pattern can remain unchanged.

When making an async invocation, the Async Service must check to see whether the service object is an instanceof AsyncDelegate. If the service object is an instanceof AsyncDelegate, then the Async Service must attempt to delegate the asynchronous call. The exact delegation operation depends on whether a Promise result is required.

138.6.1 Obtaining a Promise from an Async Delegate

If the result of the method invocation is needed by the client, then the Async Service must attempt to delegate to the async(Method,Object[]) method. The delegation proceeds as follows:

  • If the call to the Async Delegate returns a Promise, then the Promise returned by the Async Service must be resolved with that Promise.

  • If the call to the Async Delegate throws an exception, then the Promise returned by the Async Service must be failed with the exception.

  • If the Async Delegate is unable to optimize the call and returns null from the async(Method,Object[]) method, the Async Service must continue processing the async invocation, treating the service as a normal service object.

138.6.2 Delegating Fire and Forget Calls to an Async Delegate

If the result of the method invocation is not needed by the client, then the Async Service must attempt to delegate to the execute(Method,Object[]) method. This gives the Async Delegate implementation the opportunity to further optimize its processing. The delegation proceeds as follows:

  • If the call to the Async Delegate returns true, then the Promise returned by the Async Service must be resolved with null.

  • If the call to the Async Delegate throws an exception, then the Promise returned by the Async Service must be failed with the exception.

  • If the Async Delegate is unable to optimize the call and returns false from the execute(Method,Object[]) method, the Async Service must continue processing the async invocation, treating the service as a normal service object.

138.6.3 Lifecycle for Service Objects When Delegating

If an Async Delegate implementation accepts an asynchronous task, via a call to either execute(Method,Object[]) or async(Method,Object[]), then it is responsible for continuing to process the work until completion. This means that if the service implementing Async Delegate is unregistered for some reason, then the task must be properly cleaned up and succeed or fail as appropriate.

If the Async Service implementation used a service reference to obtain the service, then it must release the service object after the task has been accepted. This means that if the service object is provided by a service factory, then the service object should take extra care not to destroy its internal state when released. The service object must remain valid until all executing asynchronous tasks associated with the service object are either completed or failed.

If an Async Delegate implementation rejects an asynchronous task, by returning false or null, the Async Service implementation must take over the asynchronous invocation of the method. In this case, if the Async Service implementation used a service reference to obtain the service, the Async Service must not release the service object until the asynchronous task is completed.

If an Async Delegate implementation throws an exception and the Async Service implementation used a service reference to obtain the service, then the service object must be released immediately.

138.7 Capabilities

Implementations of the Asynchronous Service specification must provide the following capabilities.

  • A capability in the osgi.implementation namespace declaring the implemented specification to be osgi.async. This capability must also declare a uses constraint for the org.osgi.service.async and org.osgi.service.async.delegate packages. For example:

    Provide-Capability: osgi.implementation;
        osgi.implementation="osgi.async";
        version:Version="1.0";
        uses:="org.osgi.service.async,org.osgi.service.async.delegate"

    This capability must follow the rules defined for the osgi.implementation Namespace.

  • A capability in the osgi.service namespace representing the Async service. This capability must also declare a uses constraint for the org.osgi.service.async package. For example:

    Provide-Capability: osgi.service;
        objectClass:List<String>="org.osgi.service.async.Async";
        uses:="org.osgi.service.async"

    This capability must follow the rules defined for the osgi.service Namespace.

138.8 Security

Asynchronous Services implementations must be careful to avoid elevating the privileges of client bundles when calling services asynchronously, and also to avoid restricting the privileges of clients that are permitted to make a call. This means that the implementation must:

  • Be granted AllPermission. As the Async Service will always be on the stack when invoking a service object asynchronously it must be granted AllPermission so that it does not interfere with security any checks made by the service object.

  • Establish the caller's AccessControlContext in a worker thread before starting to call the service object. This prevents a bundle from being able to call a service asynchronously that it would not normally be able to call. The AccessControlContext must be collected during any call to call(), call(R) or execute().

  • Use a doPrivileged block when mediating a concrete type. A no-args constructor in a concrete type may perform actions that the client may not have permission to perform. This should not prevent the client from mediating the object, as the client is not directly performing these actions.

  • If the mediator object was created using a service reference, then the Async Services implementation must use the client's bundle context when retrieving the target service. If the service lookup occurs on a worker thread, then the lookup must use the AccessControlContext collected during the call to call(), call(R) or execute(). This prevents the client bundle from being able to make calls on a service object that they do not have permission to obtain, and ensures that an appropriately customized object is returned if the service is implemented using a service factory.

Further security considerations can be addressed using normal OSGi security rules. For example access to the Async Service can be controlled using ServicePermission[...Async, GET].

138.9 org.osgi.service.async

Version 1.0

Asynchronous Services Package Version 1.0.

Bundles wishing to use this package must list the package in the Import-Package header of the bundle's manifest. This package has two types of users: the consumers that use the API in this package and the providers that implement the API in this package.

Example import for consumers using the API in this package:

Import-Package: org.osgi.service.async; version="[1.0,2.0)"

Example import for providers implementing the API in this package:

Import-Package: org.osgi.service.async; version="[1.0,1.1)"

138.9.1 Summary

  • Async - The Asynchronous Execution Service.

138.9.2 public interface Async

The Asynchronous Execution Service. This can be used to make asynchronous invocations on OSGi services and objects through the use of a mediator object.

Typical usage:

   Async async = ctx.getService(asyncRef);
   
   ServiceReference<MyService> ref = ctx.getServiceReference(MyService.class);
   
   MyService mediator = async.mediate(ref, MyService.class);
   
   Promise<BigInteger> result = async.call(mediator.getSumOverAllValues());

The Promise API allows callbacks to be made when asynchronous tasks complete, and can be used to chain Promises.

Multiple asynchronous tasks can be started concurrently, and will run in parallel if the Async Service has threads available.

Consumers of this API must not implement this type

138.9.2.1 public Promise<R> call(R r)

<R>

The return value of the mediated call, used for type information.

Invoke the last method call registered by a mediated object as an asynchronous task. The result of the task can be obtained using the returned Promise.

Typically the parameter for this method will be supplied inline like this:

 ServiceReference<I> s = ...;
 I i = async.mediate(s, I.class);
 Promise<String> p = async.call(i.foo());

A Promise which can be used to retrieve the result of the asynchronous task.

138.9.2.2 public Promise<?> call()

Invoke the last method call registered by a mediated object as an asynchronous task. The result of the task can be obtained using the returned Promise.

Generally it is preferable to use call(Object) like this:

 ServiceReference<I> s = ...;
 I i = async.mediate(s, I.class);
 Promise<String> p = async.call(i.foo());

However this pattern does not work for void methods. Void methods can therefore be handled like this:

 ServiceReference<I> s = ...;
 I i = async.mediate(s, I.class);
 i.voidMethod()
 Promise<?> p = async.call();

A Promise which can be used to retrieve the result of the asynchronous task.

138.9.2.3 public Promise<Void> execute()

Invoke the last method call registered by a mediated object as a "fire-and-forget" asynchronous task. This method should be used by clients in preference to call() and call(Object) when no callbacks, or other features of Promise, are needed.

The advantage of this method is that it allows for greater optimization of the underlying asynchronous task. Clients are therefore likely to see better performance when using this method compared to using call(Object) or call() and ignoring the returned Promise. The Promise returned by this method is different from the Promise returned by call(Object) or call(), in that the returned Promise will resolve when the fire-and-forget task is successfully started, or fail if the task cannot be started. Note that there is no happens-before relationship and the returned Promise may resolve before or after the fire-and-forget task starts, or completes.

Typically this method is used like call():

 ServiceReference<I> s = ...;
 I i = async.mediate(s, I.class);
 i.someMethod()
 Promise<Void> p = async.execute();

A Promise representing whether the fire-and-forget task was able to start.

138.9.2.4 public T mediate(T target, Class<T> iface)

<T>

The service object to mediate.

The type that the mediated object should provide.

Create a mediator for the specified object. The mediator is a generated object that registers the method calls made against it. The registered method calls can then be run asynchronously using either the call(Object), call(), or execute() method.

The values returned by method calls made on a mediated object are opaque and should not be interpreted.

Normal usage:

 I s = ...;
 I i = async.mediate(s, I.class);
 Promise<String> p = async.call(i.foo());

A mediator for the service object.

IllegalArgumentException– If the type represented by iface cannot be mediated.

138.9.2.5 public T mediate(ServiceReference<? extends T> target, Class<T> iface)

<T>

The service reference to mediate.

The type that the mediated object should provide.

Create a mediator for the specified service. The mediator is a generated object that registers the method calls made against it. The registered method calls can then be run asynchronously using either the call(Object), call(), or execute() method.

The values returned by method calls made on a mediated object are opaque and should not be interpreted.

This method differs from mediate(Object, Class) in that it can track the availability of the specified service. This is recommended as the preferred option for mediating OSGi services as asynchronous tasks may not start executing until some time after they are requested. Tracking the validity of the ServiceReference for the service ensures that these tasks do not proceed with an invalid object.

Normal usage:

 ServiceReference<I> s = ...;
 I i = async.mediate(s, I.class);
 Promise<String> p = async.call(i.foo());

A mediator for the service object.

IllegalArgumentException– If the type represented by iface cannot be mediated.

138.10 org.osgi.service.async.delegate

Version 1.0

Asynchronous Services Delegation Package Version 1.0.

Bundles wishing to use this package must list the package in the Import-Package header of the bundle's manifest. This package contains only interfaces that are implemented by consumers.

Example import for consumers using the API in this package:

Import-Package: org.osgi.service.async.delegate; version="[1.0,2.0)"

138.10.1 Summary

  • AsyncDelegate - This interface is used by services to allow them to optimize Asynchronous calls where they are capable of executing more efficiently.

138.10.2 public interface AsyncDelegate

This interface is used by services to allow them to optimize Asynchronous calls where they are capable of executing more efficiently.

This may mean that the service has access to its own thread pool, or that it can delegate work to a remote node, or act in some other way to reduce the load on the Asynchronous Services implementation when making an asynchronous call.

138.10.2.1 public Promise<?> async(Method m, Object[] args) throws Exception

The method to be asynchronously invoked.

The arguments to be used to invoke the method.

Invoke the specified method as an asynchronous task with the specified arguments.

This method can be used by clients, or the Async Service, to optimize Asynchronous execution of methods.

When called, this method should invoke the supplied method using the supplied arguments asynchronously, returning a Promise that can be used to access the result.

If the method cannot be executed asynchronously by this method then null must be returned.

A Promise representing the asynchronous result, or null if this method cannot be asynchronously invoked.

Exception– An exception should be thrown only if there was a serious error that prevented the asynchronous task from starting. For example, the specified method does not exist on this object. Exceptions must not be thrown to indicate that the call does not support asynchronous invocation. Instead this method must return null. Exceptions must also not be thrown to indicate a failure from the execution of the underlying method. This must be handled by failing the returned Promise.

138.10.2.2 public boolean execute(Method m, Object[] args) throws Exception

The method to be asynchronously invoked.

The arguments to be used to invoke the method.

Invoke the specified method as a "fire-and-forget" asynchronous task with the specified arguments.

This method can be used by clients, or the Async Service, to optimize Asynchronous execution of methods.

When called, this method should invoke the specified method using the specified arguments asynchronously. This method differs from async(Method, Object[]) in that it does not return a Promise. This method therefore allows the implementation to perform more aggressive optimizations because the end result of the invocation does not need to be returned to the caller.

If the method cannot be executed asynchronously by this method then false must be returned.

true if the asynchronous execution request has been accepted, or false if this method cannot be asynchronously invoked by the AsyncDelegate.

Exception– An exception should be thrown only if there was a serious error that prevented the asynchronous task from starting. For example, the specified method does not exist on this object. Exceptions must not be thrown to indicate that the call does not support asynchronous invocation. Instead this method must return false. Exceptions must also not be thrown to indicate a failure from the execution of the underlying method.