Skip to content

DeviceAPI

opencode-agent[bot] edited this page May 10, 2026 · 1 revision

DeviceAPI Pattern

Interface-based API pattern in JNode that separates device access contracts from their implementations.

Overview

The DeviceAPI pattern is a core architectural pattern in JNode's driver framework. It provides a clean separation between what a device can do (the API interface) and how it does it (the implementation). This pattern enables flexible device access, runtime API discovery, and multiple API implementations per device.

At its core, every device API must extend the marker interface DeviceAPI. Devices maintain a map of registered API implementations, allowing clients to query and retrieve specific capabilities at runtime.

Key Components

Class/Interface Location Purpose
DeviceAPI core/src/driver/org/jnode/driver/DeviceAPI.java Base marker interface for all device APIs
DeviceInfoAPI core/src/driver/org/jnode/driver/DeviceInfoAPI.java Extends DeviceAPI to provide device information display
Device core/src/driver/org/jnode/driver/Device.java Holds the API registry (HashMap<Class, DeviceAPI>)
ApiNotFoundException core/src/driver/org/jnode/driver/ApiNotFoundException.java Exception thrown when requested API is not found

How It Works

API Registration and Discovery

The Device class maintains a HashMap of registered API implementations:

// From Device.java lines 62-63
private final HashMap<Class<? extends DeviceAPI>, DeviceAPI> apis =
    new HashMap<Class<? extends DeviceAPI>, DeviceAPI>();

Drivers register their API implementations when they connect to a device:

// Device.registerAPI (lines 211-229)
public final <T extends DeviceAPI> void registerAPI(Class<T> apiInterface, T apiImplementation) {
    if (!apiInterface.isInstance(apiImplementation)) {
        throw new IllegalArgumentException("API implementation does not implement API interface");
    }
    if (!apiInterface.isInterface()) {
        throw new IllegalArgumentException("API interface must be an interface");
    }
    apis.put(apiInterface, apiImplementation);
    // Also register parent interfaces
    final Class[] interfaces = apiInterface.getInterfaces();
    if (interfaces != null) {
        for (Class intf : interfaces) {
            if (DeviceAPI.class.isAssignableFrom(intf)) {
                if (!apis.containsKey(intf)) {
                    apis.put((Class<? extends DeviceAPI>) intf, apiImplementation);
                }
            }
        }
    }
}

Clients can query whether a device implements a specific API:

// Device.implementsAPI (lines 246-254)
public final boolean implementsAPI(Class<? extends DeviceAPI> apiInterface) {
    //lookup is classname based to handle multi isolate uscases
    for (Class clazz : apis.keySet()) {
        if (clazz.getName().equals(apiInterface.getName())) {
            return true;
        }
    }
    return false;
}

And retrieve the API implementation:

// Device.getAPI (lines 272-286)
public final <T extends DeviceAPI> T getAPI(Class<T> apiInterface) throws ApiNotFoundException {
    //lookup is classname based to handle multi isolate uscases
    Class apiInterface2 = null;
    for (Class clazz : apis.keySet()) {
        if (clazz.getName().equals(apiInterface.getName())) {
            apiInterface2 = clazz;
            break;
        }
    }
    final T impl = apiInterface.cast(apis.get(apiInterface2));
    if (impl == null) {
        throw new ApiNotFoundException(apiInterface.getName());
    }
    return impl;
}

Common Device API Implementations

JNode defines many specialized device APIs:

API Interface Package Purpose
BlockDeviceAPI fs/src/driver/org/jnode/driver/block/ Block device read/write operations
FSBlockDeviceAPI fs/src/driver/org/jnode/driver/block/ Filesystem-aware block device
PartitionableBlockDeviceAPI fs/src/driver/org/jnode/driver/block/ Partition management
NetDeviceAPI net/src/net/org/jnode/net/ Network device operations
CharacterDeviceAPI core/src/driver/ Character-oriented devices
DeviceInfoAPI core/src/driver/org/jnode/driver/ Device information display

Example: IDE Disk Driver

The IDE disk driver registers multiple APIs:

// fs/src/driver/org/jnode/driver/block/ide/disk/IDEDiskDriver.java (line 62)
implements IDEDeviceAPI<IBMPartitionTableEntry>, IDEConstants

Gotchas

  1. Classname-based lookup: The API lookup uses classname comparison rather than direct instanceof to handle multi-isolate use cases where the same interface may be loaded in different isolate classloaders.

  2. Parent interface auto-registration: When registering an API, parent DeviceAPI interfaces are automatically registered to the same implementation.

  3. Immutable lookup results: Device.implementedAPIs() returns an immutable key set view of the API map.

  4. No API versioning: There is no built-in mechanism for API version negotiation between client and device.

Related Pages

Clone this wiki locally