-
Notifications
You must be signed in to change notification settings - Fork 0
DeviceManagerListener
Observer interface for device discovery and binding events in JNode's driver framework.
DeviceManagerListener (core/src/driver/org/jnode/driver/DeviceManagerListener.java) is JNode's observer interface for high-level device manager events — device registration and unregistration. It allows any component to be notified whenever a device enters or leaves the system's device registry, without coupling to the device's lifecycle details.
This differs from DeviceListener (core/src/driver/org/jnode/driver/DeviceListener.java), which fires on device start and stop (the driver lifecycle within an already-registered device). DeviceManagerListener fires at a higher level: when the device is first registered with the manager and when it is about to be removed from the registry entirely.
| File | Role |
|---|---|
core/src/driver/org/jnode/driver/DeviceManagerListener.java |
The listener interface: deviceRegistered(Device), deviceUnregister(Device)
|
core/src/driver/org/jnode/driver/AbstractDeviceManager.java |
Listener registration (addListener/removeListener) and event dispatch (fireRegisteredEvent, fireUnregisterEvent) |
core/src/driver/org/jnode/driver/DeviceManager.java |
Public interface declaring addListener(DeviceManagerListener) / removeListener(DeviceManagerListener)
|
gui/src/driver/org/jnode/driver/textscreen/fb/FBConsole.java |
Canonical usage: deferred initialization of the framebuffer console |
The interface is minimal — two methods:
// core/src/driver/org/jnode/driver/DeviceManagerListener.java
public interface DeviceManagerListener {
public void deviceRegistered(Device device);
public void deviceUnregister(Device device);
}Listeners register via AbstractDeviceManager.addListener(DeviceManagerListener). The manager maintains an internal List<DeviceManagerListener>:
// AbstractDeviceManager.java
private final List<DeviceManagerListener> listeners = new LinkedList<DeviceManagerListener>();
public final void addListener(DeviceManagerListener listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
public final void removeListener(DeviceManagerListener listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}When a device is registered, AbstractDeviceManager.register() calls fireRegisteredEvent():
// Called inside register(), before start()
protected final void fireRegisteredEvent(Device device) {
final List<DeviceManagerListener> list;
synchronized (this.listeners) {
list = new ArrayList<DeviceManagerListener>(this.listeners);
}
final StopWatch sw = new StopWatch();
for (DeviceManagerListener l : list) {
sw.start();
l.deviceRegistered(device);
if (sw.isElapsedLongerThen(100)) {
BootLogInstance.get().error("DeviceManagerListener took " + sw
+ " in deviceRegistered: " + l.getClass().getName());
}
}
}The same pattern applies to fireUnregisterEvent() — called from unregister() after stopping the device but before removing it from the map.
The listener list is copied under the lock before iteration, ensuring safe concurrent modification. A StopWatch measures each callback; any listener exceeding 100ms triggers an error log.
The primary use case is deferred initialization — a component that depends on a device that may not exist yet. FBConsole in the GUI driver demonstrates this pattern:
// gui/src/driver/org/jnode/driver/textscreen/fb/FBConsole.java
public static void start() throws Exception {
final Collection<Device> devs = DeviceUtils.getDevicesByAPI(FrameBufferAPI.class);
int dev_count = devs.size();
if (dev_count > 0) {
startFBConsole(devs.iterator().next());
} else {
DeviceUtils.getDeviceManager().addListener(new DeviceManagerListener() {
public void deviceRegistered(Device device) {
if (device.implementsAPI(FrameBufferAPI.class)) {
startFBConsole(device);
}
}
public void deviceUnregister(Device device) {
// TODO stop the FBConsole
}
});
}
}This is the wait-for-device pattern: poll first, and if nothing is found, register a listener to wait asynchronously for a future device.
DeviceManagerListener |
DeviceListener |
|
|---|---|---|
| Package | org.jnode.driver |
org.jnode.driver |
| Methods |
deviceRegistered, deviceUnregister
|
deviceStarted, deviceStop
|
| Fires when | Device is registered/unregistered in the manager | Device driver starts/stops |
| Registered on | DeviceManager |
DeviceManager or Device
|
| Scope | Manager-wide (all devices) | Per-device or manager-wide |
Both listener types share the same 100ms warning threshold in AbstractDeviceManager. The distinction is between the device registry lifecycle (DeviceManagerListener) and the device driver lifecycle (DeviceListener).
-
Listener is on the manager, not the device — unlike
DeviceListenerwhich can be added directly to aDeviceinstance,DeviceManagerListeneris always registered with theDeviceManagerand receives events for all devices. -
Fire order relative to lifecycle —
deviceRegisteredis fired before the device is started (start(device)is called after the fire).deviceUnregisteris fired after the device is stopped but before it is removed from the map. - 100ms warning threshold — slow listeners affect the timing of all subsequent listener callbacks and device startup. Avoid blocking I/O in listener callbacks.
-
No filtering by device class — the listener receives every registration. Use
device.implementsAPI(SomeAPI.class)to filter. -
Anonymous inner class memory leak risk — the manager holds a strong reference to the listener. If the listener captures a large context, it won't be GC'd until explicitly removed. Always
removeListener()when done, or use weak references for long-lived listeners with short-lived implementations.
- DeviceManager — The manager this listener attaches to, including event dispatch details.
- Driver-Framework — The broader driver subsystem where this observer pattern lives.
- DeviceListener — Lower-level listener for device start/stop events (different scope).
- Plugin-System — How device finders trigger the registration events observed by this listener.
- Resource-Management — Hardware resources that devices claim at startup time.