Skip to content

InitialNaming Service Registry

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

InitialNaming Service Registry

InitialNaming is JNode's central service registry: a simple, type-keyed map used to bind and look up singleton OS services at runtime.

Overview

JNode has a lightweight service registry built on org.jnode.naming.InitialNaming. Rather than using JNDI strings as names, JNode uses Class objects as keys — this provides type-safe, refactor-friendly service lookups. Services are singleton objects (one per key) registered by plugins during boot and service startup.

The registry is initialized once during VmSystem.initialize() before any plugin code runs.

Key Components

File Purpose
org/jnode/naming/InitialNaming.java Static facade — the entry point for bind, lookup, unbind
org/jnode/naming/NameSpace.java Interface defining the contract: bind, unbind, lookup, nameSet
org/jnode/naming/AbstractNameSpace.java Base class handling listener dispatch; concrete subclasses implement the map
org/jnode/naming/NameSpaceListener.java Observer interface: serviceBound(T), serviceUnbound(T)
org/jnode/vm/VmSystem.java:122 Initializes the namespace: InitialNaming.setNameSpace(new DefaultNameSpace())

How It Works

Initialization

At VmSystem.initialize() (line 122):

InitialNaming.setNameSpace(new DefaultNameSpace());

setNameSpace can only be called once. A SecurityException is thrown on any subsequent call.

Binding a Service

Plugins bind services by passing the service's interface Class and a singleton instance:

// From WorkPlugin.java:100
InitialNaming.bind(NAME, this);  // NAME is WorkManager.class

// From DefaultPluginManager.java:77
InitialNaming.bind(NAME, this);  // NAME is PluginManager.class

// From BootLogInstance.java:60
InitialNaming.bind(BootLog.class, bootLog);

Only one service can be bound under a given Class key. Attempting to rebind throws NameAlreadyBoundException.

Looking Up a Service

Any code can look up a registered service by its Class key:

// From WorkUtils.java:44
wm = InitialNaming.lookup(WorkManager.NAME);

// From VmIsolate.java:695
piManager = InitialNaming.lookup(PluginManager.NAME);

// Convenience in BootLogInstance.java
BootLog log = BootLogInstance.get();  // calls InitialNaming.lookup(BootLog.class) internally

lookup throws NameNotFoundException if no service is bound under that Class.

Listener Pattern

NameSpaceListener<T> allows code to be notified when a service becomes available (or is removed). On registration, if the service is already bound, the listener is called immediately:

// From InitialNaming.java:57
public static <T> void addNameSpaceListener(Class<T> name, NameSpaceListener<T> l) {
    NAME_SPACE.addNameSpaceListener(name, l);
}

The AbstractNameSpace implementation handles the listener registry and fires callbacks when bind/unbind occurs. This is particularly useful for subsystems that depend on services that are initialized later.

Accessing Bound Names

InitialNaming.nameSet() returns all currently registered service keys (as a Set<Class<?>>). This can be used for introspection or debugging.

Typical Boot Order

VmSystem.initialize()
  → InitialNaming.setNameSpace()           // create the registry
  → BootLogImpl.initialize()
     → InitialNaming.bind(BootLog.class, bootLog)
  → DefaultPluginManager creation
     → InitialNaming.bind(PluginManager.class, pm)
  → [Plugins start, each bind their own services]
  → Other subsystems look up services as needed

Why Class Keys?

Using Class objects as keys instead of strings:

  • Type safety: The compiler verifies the return type at the call site
  • No typos: Refactoring a class name automatically updates all lookups
  • Single instance: Each service class has at most one singleton in the registry
  • Impossible to guess: No string name collision issues

Gotchas

  • Once-only initialization: setNameSpace can only be called once. The namespace is effectively immutable after first boot.
  • NameNotFoundException on missing service: lookup fails if the service hasn't been bound yet. Services must be started in the correct dependency order.
  • No lazy instantiation: The registry holds direct object references. Lazy service creation must be implemented by the service itself.
  • No namespace hierarchy: Unlike JNDI, there is only a flat map of ClassObject. No sub-contexts.
  • Observer fires on add: When you call addNameSpaceListener, if the service is already bound, your listener is called synchronously from within addNameSpaceListener.

Related Pages

Clone this wiki locally