Skip to content

Integrate the model graph tools into halOP #288

Description

@hpehl

Blueprint: halOP & Model Graph Tools (MGT) Integration Design

1. Executive Summary

This document serves as an architectural blueprint for integrating Model Graph Tools (MGT) into halOP (the next-generation management console for WildFly).

Instead of rebuilding complex graphical visualization frontends within the browser or bundling massive, static datasets inside the console application, this design patterns the integration as a Sidecar Knowledge Base. halOP queries a running, version-matched MGT container via its REST API to enable advanced semantic search, cross-reference capabilities, and instant deep-linking into the appropriate configuration spaces within the console.


2. Architectural Architecture: The Sidecar Pattern

In production and development environments alike, halOP remains completely stateless and lightweight, communicating with the target WildFly instance over standard DMR/HTTP.

When an administrator deploys the corresponding versioned MGT container (e.g., via Podman or Docker using mgt start <version>), halOP discovers this optional endpoint and treats it as a read-only, high-performance schema index.

The MGT container bundles a Quarkus REST API (model-graph-tools/rest-api) that sits between halOP and the Neo4j database. nginx inside the container proxies /api/* requests to the Quarkus process, so no new ports are exposed — everything is reachable through the existing MGT HTTP port.

                  ┌────────────────────────────────────────────────────────┐
                  │                  MGT Container                         │
                  │                                                        │
                  │  ┌──────────┐     ┌──────────────┐     ┌────────────┐  │
                  │  │  nginx   │────►│  REST API    │────►│   Neo4j    │  │
                  │  │  :7474   │     │  (Quarkus)   │     │ (Bolt)     │  │
                  │  │          │     │  :8080       │     │            │  │
                  │  └──────────┘     └──────────────┘     └────────────┘  │
                  │       │                                                │
                  │       ├── /api/*  → REST API                           │
                  │       └── /*      → Neo4j Browser                      │
                  └───────────────────┬────────────────────────────────────┘
                                      │
                                      │ HTTP / JSON
                                      ▼
┌──────────────────┐   DMR/HTTP    ┌───────────────────────┐
│ Target WildFly   ◄──────────────►│   halOP Console       │
│ Runtime Instance │               │ (Browser-based / J2CL)│
└──────────────────┘               └───────────────────────┘

Key Separation of Concerns

  • WildFly Runtime: Manages the actual configuration state, server runtime, and execution of management operations.
  • MGT Container: Contains the Neo4j graph database with the static metadata graph of the matching WildFly release, plus a Quarkus REST API that provides typed search, version, and capability-reference endpoints.
  • halOP Browser App: Orchestrates the UI, queries the runtime for state, queries the MGT REST API for discoverability, and translates results into active UI navigation.

3. Search & Deep-Link Sequence Flow

The primary user interaction pattern is a global "Super Search" where semantic queries map straight to concrete configuration screens.

Scenario: Admin searches for a specific operational capability or attribute

  1. Input: The user types max-post-size or a capability like org.wildfly.security.http-authentication-factory into the halOP global search bar.
  2. Parallel Dispatch:
    • Local Dispatch: halOP queries the current runtime via DMR (for active deployment names, active server instances, etc.).
    • Graph Dispatch: halOP fires a search request to the MGT REST API endpoint.
  3. Graph Evaluation: The REST API runs Cypher queries against Neo4j, scanning resources, attributes, and capabilities.
  4. Payload Return: The REST API responds with matching results containing:
    • Element type (Resource, Attribute, or Capability)
    • The name and text description / documentation
    • The absolute management model path (e.g., /subsystem=undertow/server=*/http-listener=*)
    • For attribute results: the attribute name for field-level highlighting
  5. UI Rendering: halOP renders a distinct search result card highlighting the exact context.
  6. Navigation: Clicking the result converts the management path into an AddressTemplate and calls RouteRegistry.goTo(template), which resolves the best matching route and navigates there (see section 4).

4. Technical Strategy: Graph to UI Routing Map (✅ Implemented)

The routing infrastructure for mapping management model addresses to UI routes is implemented and operational. The following classes provide the bidirectional bridge between AddressTemplates and Elemento router routes:

Core Classes

Class Module Purpose
RouteBinding ui Record that co-locates a route string, its wildcard AddressTemplate, and two conversion lambdas (toTemplate for route→template, toRoute for template→route)
RouteRegistry ui Central registry with lookup by route (byRoute) or by template (byTemplate — best-prefix match via TemplateMatcher), plus a goTo(AddressTemplate) convenience method that navigates to the best match or falls back
TemplateMatcher meta Prefix-matching algorithm: compares segments left-to-right, picks the longest prefix match, breaks ties by exact (non-wildcard) value count
KnownRoutes op Constants for all registered route patterns (e.g. /configuration/subsystem/:name/:selection?)
RouteRegistryProducer op CDI producer that wires up all RouteBindings — the single place to add new route mappings

Currently Registered Bindings

AddressTemplate Route Pattern Parameters
interface=* /configuration/interface/:name name
path=* /configuration/path/:name name
socket-binding-group=* /configuration/socket-binding-group/:name name
socket-binding-group=*/socket-binding=* /configuration/socket-binding-group/:group/socket-binding/:name group, name
subsystem=* /configuration/subsystem/:name/:selection? name, selection (optional)
system-property=* /configuration/system-property/:name name

The fallback route /management-model/:selection? handles any template that has no dedicated page.

MGT Integration Point

Navigating from an MGT search result to the correct halOP page is a one-liner. The MGT REST API returns addresses with a leading / (e.g. /subsystem=undertow/server=*/http-listener=*), and AddressTemplate.ofTrusted() handles the leading slash transparently:

// MGT REST API returns an address like "/subsystem=undertow/server=default-server/http-listener=default"
AddressTemplate template = AddressTemplate.ofTrusted(searchResult.address());
routeRegistry.goTo(template);

RouteRegistry.goTo() uses TemplateMatcher to find the best-prefix binding (here: subsystem=*), extracts the route parameters via the binding's toRoute lambda, and navigates via PlaceManager.goTo(). If no binding matches, it falls back to the generic management model page.

Remaining Work: Wildcard Disambiguation

MGT search results use wildcard paths (e.g. /subsystem=undertow/server=*/http-listener=*) because the graph represents the static schema. When a search result contains wildcards:

  1. halOP must query the running WildFly instance to resolve wildcards to concrete resource names.
  2. If a single instance exists, navigate directly.
  3. If multiple instances exist, prompt the user with a picker (e.g. "Which server? [default-server / public-server]") before navigating.

This disambiguation logic should live between the search UI and RouteRegistry.goTo() — the registry itself always expects resolved templates.


5. REST API Endpoints (✅ Available)

The MGT container now includes a purpose-built Quarkus REST API (model-graph-tools/rest-api) that wraps the Neo4j database with typed, JSON-over-HTTP endpoints. halOP no longer needs to query Neo4j's HTTP transaction endpoint directly — it uses these REST endpoints instead.

The API is reachable through the existing MGT HTTP port via nginx reverse proxy (e.g., http://localhost:7410/api/...).

Endpoints

GET /api/search?q={term}&limit={limit}

Unified search across resources, attributes, and capabilities. Returns results matching by name or description, excluding deployment-scoped resources (which aren't navigable in halOP's configuration UI).

Parameters:

Parameter Type Default Description
q String (required) Search term
limit Integer 10 Max results per category

Response:

{
  "results": [
    {
      "type": "Resource",
      "name": "buffer-pool",
      "description": "The worker buffer pool.",
      "address": "/subsystem=io/buffer-pool=*"
    },
    {
      "type": "Attribute",
      "name": "buffer-pool",
      "description": "The buffer pool used by the listener.",
      "address": "/subsystem=undertow/server=*/http-listener=*",
      "attributeName": "buffer-pool"
    },
    {
      "type": "Capability",
      "name": "org.wildfly.io.buffer-pool",
      "address": "/subsystem=io/buffer-pool=*"
    }
  ]
}

Each result contains the parent resource's address for direct navigation via AddressTemplate.ofTrusted() → RouteRegistry.goTo(). For attribute results, the attributeName field enables halOP to scroll to and highlight the specific form field after navigation. Null fields are omitted from the JSON response.

GET /api/version

Returns the WildFly version and source type of the loaded model graph. Used by halOP for version synchronization (see section 7).

Response:

{
  "version": "41.0.0",
  "sourceType": "wildfly"
}

The sourceType is "wildfly" or "eap".

GET /api/capability/{name}/references

Returns all attributes that reference a given capability, along with their parent resources. Used for the "Where is this used?" capability explorer (see section 6B).

Response:

{
  "capability": "org.wildfly.io.buffer-pool",
  "references": [
    {
      "attributeName": "buffer-pool",
      "resourceName": "http-listener",
      "resourceAddress": "/subsystem=undertow/server=*/http-listener=*"
    },
    {
      "attributeName": "buffer-pool",
      "resourceName": "https-listener",
      "resourceAddress": "/subsystem=undertow/server=*/https-listener=*"
    }
  ]
}

Connectivity & Health

halOP checks MGT availability via a simple HTTP request:

GET /api/version

A 200 OK with a valid JSON response means the MGT REST API is online and the graph database is loaded. This replaces the previous Cypher-based ping approach.

Additionally, Quarkus health checks are available at /q/health for container-level monitoring.


6. UI/UX Integration Points

A. The "Super Search" Omnibar

  • Integrate an extended results section in the top navigation search.
  • Visual tagging: Clearly differentiate [Resource], [Attribute], and [Capability] results using distinct PatternFly label styles.
  • Clicking a result triggers wildcard disambiguation (section 4) followed by RouteRegistry.goTo().
  • For attribute results, use the attributeName field to scroll to and highlight the specific form field after navigation.

B. Inline Capability Explorer & "Where is this Used?" Drawer

  • When editing a resource that requires a capability, halOP can display an informational icon.
  • Clicking it queries the MGT REST API: GET /api/capability/{capabilityName}/references.
  • Displays a side-drawer showing a clean list of other subsystems dependent on or provisioning that exact token, with one-click deep links via RouteRegistry.goTo().

C. Graceful Degradation (Fallback Mode)

  • On application startup, halOP sends a version request to the configured MGT base URL (GET /api/version).
  • If Offline: The extended graph-search functionality is silently disabled or greyed out with a subtle tooltip ("Connect an MGT container to enable semantic cross-reference search"). No console errors break the core application.
  • If Online: The search features light up automatically.

7. Critical Engineering Challenges & Mitigations

1. Cross-Origin Resource Sharing (CORS)

  • The Problem: The halOP UI executes inside a browser sandbox served from WildFly's management port (e.g., 9990). Direct HTTP requests to an arbitrary MGT container port (e.g., 7474) will be rejected by browser security models.
  • The Solution:
    1. Configure the MGT container's nginx to inject CORS headers for /api/* responses.
    2. Alternatively, design a lightweight proxy path into the halOP standalone launcher if distributed together, or request users to map a simple reverse proxy path.

2. Version Synchronization

  • The Problem: Querying a WildFly 40 model graph while managing a WildFly 34 runtime will result in misleading search results, broken links, or missing attribute references.
  • The Solution: Upon connection, halOP reads the management model version from the local runtime via a root DMR read-attribute operation, then calls GET /api/version on the MGT REST API and compares the version and sourceType fields. A warning banner is shown if a mismatch occurs.

3. Neo4j HTTP API Deprecation ✅ Resolved

  • The Problem: Neo4j's HTTP transaction endpoint (/db/neo4j/tx/commit) is deprecated in favor of the Query API.
  • Resolution: halOP no longer queries Neo4j directly. The MGT REST API encapsulates all Neo4j interaction via the Bolt protocol. Any future Neo4j API changes are handled inside the REST API, transparent to halOP.

8. Next Steps

  1. Prototype the Router Bridge: Write a utility class in halOP (MgtPathTranslator.java) that takes a standard DMR absolute path sequence and outputs a valid halOP PlaceRequest. ✅ Implemented via RouteBinding / RouteRegistry / TemplateMatcher.
  2. Define the Cypher Payload Schema: Determine the exact JSON return shape for a generic full-text index query on the MGT Neo4j instance. ✅ Replaced by the MGT REST API with typed endpoints (see section 5).
  3. Build MgtService: CDI bean in halOP that manages the HTTP connection to the MGT REST API (/api/search, /api/version, /api/capability/{name}/references), deserializes JSON responses, and handles graceful degradation when offline.
  4. Implement Wildcard Disambiguation: Build a UI component that resolves wildcard segments against the running WildFly instance and prompts the user when multiple instances exist (see section 4).
  5. Draft the Search Elemento Component: Build the Super Search omnibar using Elemento that handles async callbacks from both the runtime DMR endpoint and the external MGT REST API, rendering typed result cards with RouteRegistry.goTo() navigation.
  6. Add More Route Bindings: As new resource pages are added to halOP, register their RouteBindings in RouteRegistryProducer — no architectural changes needed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions