Shared Interfaces

Principle

The Shared Interface mechanism provided by the Core Engine is an object communication bus based on plain Java interfaces where method calls are allowed to cross Sandboxed Applications boundaries without relying on Kernel APIs.

The Shared Interface mechanism is the cornerstone for designing reliable Service Oriented Architectures. Communication is based on the sharing of interfaces defining APIs (Contract Oriented Programming).

The basic schema:

  • A provider application publishes an implementation for a shared interface into a system registry.

  • A user application retrieves the implementation from the system registry and directly calls the methods defined by the shared interface.

Shared Interface Call Mechanism

Shared Interface Call Mechanism

The Shared Interface mechanism is based on automatic proxy objects created by the Core Engine. This offers a reliable way for users to handle broken links in case the provider application has been stopped or uninstalled.

Applications with a Shared Interface must provide a dedicated implementation (called the Proxy class implementation). Its main goal is to perform the remote invocation and provide a reliable implementation regarding the interface contract even if the remote application fails to fulfill its contract (unexpected exceptions, application killed, …). The Core Engine will allocate instances of this Proxy class when an implementation (of the Shared Interface) owned by another application is being transferred to this application.

Shared Interfaces Proxy Overview

Shared Interfaces Proxy Overview

This mecanism is formally specified in the [KF] specification.

Shared Interface Usage

Usage of a Shared Interface follows these steps:

  1. Define the Shared Interface:

    1. Define the Java interface

    2. Implement the proxy for the interface

    3. Register the interface as a Shared Interface

  2. From the provider application,

    1. Create an instance of this Shared Interface

    2. Register the instance to a KF service registry

  3. From the consumer application,

    1. Retrieve a proxy of the instance from the KF service registry

    2. Call methods of the instance proxy.

Define the Shared Interface

Define the Java Interface

The definition of a Shared Interface starts by defining a standard Java interface. For example:

package mypackage;
public interface MyInterface {
    void foo();
}

A Shared Interface includes all methods it declares, along with those inherited from its super types. It can extend any interface, including Feature interfaces (which may or may not be declared as Shared Interfaces) and Kernel interfaces.

Some restrictions apply to Shared Interfaces compared to standard Java interfaces:

  • Types for parameters and return values must be transferable types;

  • Thrown exceptions must be classes owned by the Kernel.

Implement the Proxy Class

A proxy class is implemented and executed on the client side.

with the following specification:

  • its fully qualified name is the shared interface fully qualified name append with Proxy.

  • it extends the Proxy class.

  • it implements the Shared Interface

  • it provides an implementation of all interface methods

Each method of the implemented interface must be defined according to the following pattern:

package mypackage;

public class MyInterfaceProxy extends Proxy<MyInterface> implements MyInterface {
    @Override
    public void foo(){
        try {
            invoke(); // perform remote invocation
        } catch (Throwable e) {
            // Handle any errors thrown during the remote call, including dead Feature.
            // Implement a behavior that complies with the method specification.
            // i.e. return a valid error code or throw a documented exception.
            // Logging traces for debug can also be added here.
        }
    }
}

Each implemented method of the proxy class is responsible for performing the remote call and catching all errors from the server side and to provide an appropriate answer to the client application call according to the interface method specification (contract).

The Proxy class implementation section documents how to perform the remote invocation.

Register the Shared Interface

To declare an interface as a Shared Interface, it must be registered in a Shared Interfaces identification file. A Shared Interface identification file is an XML file with the .si filename extension and the following format:

<sharedInterfaces>
    <sharedInterface name="mypackage.MyInterface"/>
</sharedInterfaces>

Shared Interface identification files must be placed at the root of the application classpath, typically it is defined in the src/main/resources folder.

Use the Shared Interface at Runtime

Projects Structure

Both the consumer and the provider applications must have the Java interface, the proxy class and the identification file on the classpath in order to be able to use the Shared Interface.

Typically, the 3 files can be defined in an Add-On Library that both application projects depend on.

Create and Share an instance of a Shared Interface

The provider application can instantiate the Java interface. For example:

MyInterface myInstance = new MyInterface() {
    @Override
    public void foo() {
        System.out.println("Hello world!");
    }
};

In order to share the instance with other applications, the provider application must register the instance with some registry owned by the Kernel (see Communication between Kernel and Feature for details) like so:

ServiceFactory.register(MyInterface.class, myInstance);

Retrieve and Use a Proxy of a Shared Interface Instance

The consumer application can then retrieve the instance from the Kernel registry like so:

MyInterface otherAppInstance = ServiceFactory.getService(MyInterface.class);
// otherAppInstance is actually an instance of the proxy class owned by the consumer application

Then it can call the interface methods transparently:

otherAppInstance.foo(); // remote invocation through the proxy

Transferable Types

In the process of a cross-application method call, parameters and return value of methods declared in a Shared Interface must be transferred back and forth between application boundaries.

Shared Interface Parameters Transfer

Shared Interface Parameters Transfer

The following table describes the rules applied depending on the element to be transferred.

Shared Interface Types Transfer Rules

Type

Owner

Instance Owner

Rule

Base type

N/A

N/A

Passing by value. (boolean, byte, short, char, int, long, double, float)

Any Class, Array or Interface

Kernel

Kernel

Passing by reference

Any Class, Array or Interface

Kernel

Application

Kernel specific. Converted to a target Feature object if the Kernel has registered a Kernel type converter, otherwise Forbidden.

Array of base types

Any

Application

Clone by copy

Arrays of references

Any

Application

Clone and transfer rules applied again on each element (recursively)

Shared Interface

Application

Application

Passing by indirect reference (Proxy creation).

Any Class, Array or Interface

Application

Application

Forbidden

Objects created by an Application which type is owned by the Kernel can be transferred to another Application provided this has been authorized by the Kernel. When an argument transfer is forbidden, the call is abruptly stopped and an java.lang.IllegalAccessError is thrown by the Core Engine.

The list of Kernel types that can be transferred is Kernel specific, so you have to consult your Kernel specification. The table below lists some well-known types that your Kernel likely can allow to be transferred through a Shared Interface, along with their behaviors. [2].

Transfer Rules for well-known Kernel Types

Type

Rule

java.lang.Boolean

Clone by copy

java.lang.Byte

Clone by copy

java.lang.Character

Clone by copy

java.lang.Short

Clone by copy

java.lang.Integer

Clone by copy

java.lang.Float

Clone by copy

java.lang.Long

Clone by copy

java.lang.Double

Clone by copy

java.lang.String

Clone by copy

java.io.InputStream

Create a Proxy reference

java.util.Date

Clone by copy

java.util.List<T>

Clone by copy with recursive element conversion

java.util.Map<K,V>

Clone by copy with recursive keys and values conversion

Implementing the Proxy Class

Remote invocation methods are defined in the super class ej.kf.Proxy and are named invokeXXX() where XXX is the kind of return type.

Proxy Remote Invocation Built-in Methods

Invocation Method

Usage

void invoke()

Remote invocation for a proxy method that returns void

Object invokeRef()

Remote invocation for a proxy method that returns a reference

boolean invokeBoolean(), byte invokeByte(), char invokeChar(), short invokeShort(), int invokeInt(), long invokeLong(), double invokeDouble(), float invokeFloat()

Remote invocation for a proxy method that returns a base type

As this class is part of the Application, the developer has the full control on the Proxy implementation and is free to insert additional code such as logging calls and errors for example. It is also possible to have different proxy implementations for the same Shared Interface in different applications.