# AdaptorManager in Bella OpenAPI: How Protocol Requests Are Routed to AI Providers

> Discover how Bella OpenAPI's AdaptorManager routes requests to AI providers using a thread-safe map for efficient endpoint and protocol matching. Learn about this core component.

- Repository: [Ke Technologies/bella-openapi](https://github.com/lianjiatech/bella-openapi)
- Tags: internals
- Published: 2026-03-06

---

**AdaptorManager is a singleton registry that maintains a thread-safe map of protocol adapters, enabling Bella OpenAPI to route incoming requests to the correct AI provider implementation based on endpoint and protocol matching.**

The AdaptorManager serves as the central routing authority in Bella OpenAPI (lianjiatech/bella-openapi), managing the discovery and dispatch of requests to provider-specific implementations like OpenAI, Gemini, and Azure. This component bridges the generic Bella API surface with native AI provider protocols, ensuring that each request reaches the appropriate adapter for translation and execution.

## AdaptorManager Singleton Design and Registry Structure

The AdaptorManager follows the singleton pattern to maintain a centralized, thread-safe registry of all available protocol adapters. At its core, the manager stores a nested concurrent hash map where the outer key represents the endpoint name (e.g., `chat/completions`), and the inner map associates adapter class names with their instantiated implementations.

In [`api/server/src/main/java/com/ke/bella/openapi/protocol/AdaptorManager.java`](https://github.com/lianjiatech/bella-openapi/blob/main/api/server/src/main/java/com/ke/bella/openapi/protocol/AdaptorManager.java), the registry is defined as:

```java
public class AdaptorManager {
    private static final AdaptorManager INSTANCE = new AdaptorManager();
    private final Map<String, Map<String, IProtocolAdaptor>> adaptors = new ConcurrentHashMap<>();

    private AdaptorManager() { }

    public static AdaptorManager getInstance() {
        return INSTANCE;
    }
    …
}

```

**Key design details:**
- **Outer map key**: The endpoint path (e.g., `chat/completions`, `audio/transcriptions`)
- **Inner map key**: The simple class name of the adapter (e.g., `OpenAIAdaptor`, `GeminiAdaptor`)
- **Value**: The `IProtocolAdaptor` implementation instance

This structure allows multiple adapters to register for the same endpoint, supporting protocol diversity within a single API surface.

## Registering Adapters with AdaptorManager at Startup

Registration occurs automatically during Spring Boot initialization through [`api/server/src/main/java/com/ke/bella/openapi/configuration/BellaAutoConf.java`](https://github.com/lianjiatech/bella-openapi/blob/main/api/server/src/main/java/com/ke/bella/openapi/configuration/BellaAutoConf.java). The configuration class injects all beans implementing `IProtocolAdaptor` and registers them with the singleton manager.

```java
@Bean
public AdaptorManager adaptorManager(@Autowired List<IProtocolAdaptor> adaptors) {
    AdaptorManager manager = AdaptorManager.getInstance();
    adaptors.forEach(adaptor -> manager.register(adaptor.endpoint(), adaptor));
    return manager;
}

```

Each adapter implements the `endpoint()` method to declare which Bella OpenAPI endpoint it handles. During startup, the manager populates its internal map by calling `register(String endpoint, IProtocolAdaptor adaptor)`, making the adapters available for runtime routing without manual configuration.

## Querying AdaptorManager for Protocol Support

The AdaptorManager exposes several query methods to verify adapter availability and retrieve implementations:

- **`getProtocols(String endpoint)`**: Returns the set of registered protocol names for a specific endpoint.
- **`support(String endpoint, String protocol)`**: Validates whether a given protocol adapter exists for the requested endpoint.
- **`getProtocolAdaptor(String endpoint, String protocol)`**: Retrieves the raw `IProtocolAdaptor` interface implementation.
- **`getProtocolAdaptor(String endpoint, String protocol, Class<T> clazz)`**: Returns the adapter cast to a concrete subclass (e.g., `CompletionAdaptor.class`).

These methods enable both the routing layer and controllers to validate capabilities before attempting request execution.

## Request Routing Through AdaptorManager

### ChannelRouter Protocol Filtering

When a request arrives, the `ChannelRouter` in [`api/server/src/main/java/com/ke/bella/openapi/protocol/ChannelRouter.java`](https://github.com/lianjiatech/bella-openapi/blob/main/api/server/src/main/java/com/ke/bella/openapi/protocol/ChannelRouter.java) first queries the database for candidate channels (provider instances), then filters these channels by protocol support using the AdaptorManager:

```java
List<ChannelDB> endpointMatched = channels.stream()
        .filter(channel -> AdaptorManager.getInstance()
                .support(endpoint, channel.getProtocol()))
        .collect(Collectors.toList());

```

Only channels with a registered adapter for the requested endpoint survive this filter. The router subsequently applies safety-level, quota, and rate-limit checks to select the final channel for execution.

### Controller Adapter Retrieval

After the router selects a channel, controllers obtain the concrete adapter instance to process the request. The `ChatController` in [`api/server/src/main/java/com/ke/bella/openapi/endpoints/ChatController.java`](https://github.com/lianjiatech/bella-openapi/blob/main/api/server/src/main/java/com/ke/bella/openapi/endpoints/ChatController.java) demonstrates this pattern:

```java
// ChatController – completion request
CompletionAdaptor<?> adaptor = adaptorManager.getProtocolAdaptor(
        endpoint, protocol, CompletionAdaptor.class);
ChatResponse resp = adaptor.completion(request);

```

Every endpoint controller follows this delegation model: query the AdaptorManager for the specific implementation, then invoke the provider-specific translation logic.

## Extending AdaptorManager with Custom Adapters

### Registering a New Provider Adapter

To add support for a new AI provider, implement `IProtocolAdaptor` and declare it as a Spring component. The framework automatically discovers and registers the adapter.

```java
// Example: a new provider called "FooAI"
@Component
public class FooCompletionAdaptor implements IProtocolAdaptor<CompletionRequest, CompletionResponse> {

    @Override
    public String endpoint() {
        return "chat/completions";          // the Bella endpoint this adaptor handles
    }

    @Override
    public String getDescription() {
        return "FooAI completion service";
    }

    // implementation of the actual call to FooAI …
}

```

No additional registration code is required—the `BellaAutoConf` class handles injection into the AdaptorManager during context refresh.

### Manual Adapter Lookup

For specialized use cases requiring direct adapter access, obtain the singleton instance and query by endpoint and protocol:

```java
AdaptorManager manager = AdaptorManager.getInstance();

// Verify support first (optional)
if (!manager.support("chat/completions", "FooCompletionAdaptor")) {
    throw new IllegalArgumentException("Protocol not supported");
}

// Get the concrete adaptor
FooCompletionAdaptor adaptor = manager.getProtocolAdaptor(
        "chat/completions", "FooCompletionAdaptor", FooCompletionAdaptor.class);

// Use it
CompletionResponse resp = adaptor.completion(myRequest);

```

## Summary

- **AdaptorManager** is a singleton registry in [`api/server/src/main/java/com/ke/bella/openapi/protocol/AdaptorManager.java`](https://github.com/lianjiatech/bella-openapi/blob/main/api/server/src/main/java/com/ke/bella/openapi/protocol/AdaptorManager.java) that maps Bella OpenAPI endpoints to protocol-specific adapter implementations.
- **Registration** occurs automatically at startup via [`api/server/src/main/java/com/ke/bella/openapi/configuration/BellaAutoConf.java`](https://github.com/lianjiatech/bella-openapi/blob/main/api/server/src/main/java/com/ke/bella/openapi/configuration/BellaAutoConf.java), which injects all `IProtocolAdaptor` beans into the manager.
- **Routing** relies on the `support()` method to filter database channels in [`ChannelRouter.java`](https://github.com/lianjiatech/bella-openapi/blob/main/ChannelRouter.java), ensuring only compatible providers are considered for request handling.
- **Execution** follows a delegation pattern where controllers retrieve typed adapters via `getProtocolAdaptor()` and invoke provider-specific translation methods.
- **Extensibility** is achieved by implementing `IProtocolAdaptor` and declaring the class as a Spring component, requiring no manual registry configuration.

## Frequently Asked Questions

### What is the primary responsibility of AdaptorManager in Bella OpenAPI?

AdaptorManager maintains a centralized registry of protocol adapters and serves as the lookup authority for routing requests. It enables the framework to dispatch requests to the correct provider-specific implementation (such as OpenAI or Gemini) based on the endpoint path and protocol identifier, abstracting provider differences from the core API layer.

### How does AdaptorManager support multiple AI providers for the same endpoint?

The manager stores a nested map structure where each endpoint key maps to multiple protocol adapters. During routing, `ChannelRouter` filters candidate channels by checking `AdaptorManager.support()`, allowing the system to maintain parallel implementations for providers like Azure, OpenAI, and Gemini under a single `chat/completions` endpoint.

### Can developers add custom protocol adapters without modifying core Bella OpenAPI code?

Yes. Developers implement the `IProtocolAdaptor` interface, annotate the class with `@Component`, and implement the `endpoint()` method to declare the target API path. Spring Boot's component scanning automatically injects the adapter into `BellaAutoConf`, which registers it with the AdaptorManager singleton at startup without requiring changes to the core registry logic.

### What happens if a request specifies a protocol with no registered adapter?

If `AdaptorManager.support()` returns false for the requested endpoint and protocol combination, the `ChannelRouter` filters out all channels associated with that protocol, resulting in an empty candidate list. This typically causes the routing layer to return an error indicating that no available channel supports the requested protocol, preventing invalid requests from reaching the execution stage.