Skip to content

feat(server): adapt Hubble 2.0 frontend APIs and implement default graph/role management#1

Open
Yeaury wants to merge 18 commits intomasterfrom
feat/hubble-api-compatibility
Open

feat(server): adapt Hubble 2.0 frontend APIs and implement default graph/role management#1
Yeaury wants to merge 18 commits intomasterfrom
feat/hubble-api-compatibility

Conversation

@Yeaury
Copy link
Copy Markdown
Owner

@Yeaury Yeaury commented May 6, 2026

Summary

  • Add Hubble 2.0 compatible REST API endpoints for graph profile, default graph/role management, and schema template CRUD
  • Implement setDefaultGraph/unsetDefaultGraph/getDefaultGraph in both StandardAuthManager (standalone) and StandardAuthManagerV2 (PD mode)
  • Implement default role management (createDefaultRole, isDefaultRole, etc.) for GraphSpace
  • Fix fabricated belong ID bug: replace string-constructed edge IDs with actual graph traversal (findBelongBinding) to correctly detect/delete existing HugeBelong edges
  • Fix HugeUser.initSchemaIfNeeded to perform incremental schema upgrade so existing deployments get the user_nickname property key
  • Fix SchemaTemplateAPI logger class name, add ensurePdModeEnabled guards to all schema template endpoints
  • Fix compilation errors: wrong imports (commons-langcommons-lang3), duplicate isPrefix() method, wrong HugeException import path
  • Route default graph operations through AuthManager unconditionally (remove erroneous isPDEnabled() no-ops)

Test plan

  • Build passes: mvn compile -DskipTests
  • Standalone (RocksDB) mode: set/get/unset default graph works without PD
  • PD mode: default graph and role bindings are idempotent (repeated set/unset does not throw)
  • Existing deployments: HugeUser schema upgrade adds user_nickname without recreating the vertex label

Yeaury added 18 commits April 24, 2026 10:53
- Add listProfile endpoint with default graph sorting and prefix filtering
- Add setDefault/unsetDefault/getDefault endpoints for default graph management
- Add manage(PUT) endpoint for graph nickname update
- Add createByForm for form-urlencoded graph creation compatibility
- Auto-fill HStore/PD defaults (backend/serializer/store) during graph creation
- Add setDefaultRole/checkDefaultRole/deleteDefaultRole in GraphSpaceAPI
- Add checkDefaultRole endpoint in ManagerAPI
- Add default role interfaces in AuthManager
- Implement default role CRUD in StandardAuthManager and StandardAuthManagerV2
- Add stub proxy methods in HugeGraphAuthProxy
- Add new SchemaTemplateAPI with list/get/create/update/delete operations
- Fix package path from api.profile to api.space
- Use HugeGraphAuthProxy.username() instead of authManager.username()
…#3008)

- fix: use @POST/@delete for setDefault/unsetDefault (REST semantics)
- fix: add null/empty validation before role field access in GraphSpaceAPI
  to prevent NPE in setDefaultRole/checkDefaultRole/deleteDefaultRole
- fix: change isPrefix to private static and guard nickname null in
  GraphSpaceAPI and GraphsAPI
- fix: ConfigUtil.writeConfigToString always returns JSON regardless
  of whether config was loaded from file, fixing listProfile endpoint
- fix: add @RolesAllowed annotations to SchemaTemplateAPI endpoints
- fix: use ForbiddenException (403) instead of HugeException (400)
  for authorization failures in SchemaTemplateAPI and GraphSpaceAPI
- fix: correct LOG placeholder count in SchemaTemplateAPI.delete
- fix: use HugeException ('%s') format instead of SLF4J '{}' format
- fix: replace com.alipay StringUtils with commons-lang3 in ManagerAPI
- fix: add @consumes and checkUpdate() validation to SchemaTemplate.update
- fix: add ensurePdModeEnabled guard to ManagerAPI.checkDefaultRole
- fix: guard configs null access in GraphsAPI.create clone branch
… mode

## Background

Hubble 2.0 previously relied exclusively on PD mode (distributed HStore
backend). This PR makes the server-side APIs fully compatible with the
community default: single-node RocksDB without PD/HStore, so that Hubble
remains functional out of the box for all deployment modes.

## Core bug fixes

### GraphsAPI
- Fix `create()`: `backend=hstore` / `serializer=binary` defaults are now
  only injected when `manager.isPDEnabled()` is true, preventing graph
  creation failures on standalone RocksDB deployments.
- Fix `manage()`: replace `exist.nickname(nickname)` (in-memory only) with
  `manager.updateGraphNickname()`, which persists the change to PD meta
  storage in distributed mode and gracefully falls back to in-memory update
  in standalone mode.
- Fix `manage()`: relax `actionMap.size() == 2` validation to
  `containsKey(GRAPH_ACTION)`, so extra fields from the frontend no longer
  cause spurious 400 errors.
- Guard `getDefaultGraph()`, `setDefault()`, `unsetDefault()`, and
  `getDefault()` with `isPDEnabled()` checks; return empty results in
  standalone mode instead of throwing NPE.
- Fix `listProfile()`: guard `getDefaultGraph()` call with `isPDEnabled()`;
  add null-safe fallback for `gs.nickname()` in non-PD mode.

### GraphManager
- `isExistedGraphNickname()`: add non-PD branch that scans in-memory graphs
  instead of accessing the uninitialized `metaManager`, preventing NPE in
  standalone mode.
- New `updateGraphNickname()`: updates in-memory graph instance first, then
  persists nickname to `metaManager` only in PD mode.

### ConfigUtil
- `writeConfigToString()`: always serializes config to JSON (previously
  could emit raw properties format), fixing `listProfile` deserialization.
- New `isSensitiveKey()`: filters keys containing `password`, `secret`,
  `token`, `credential`, `private_key`, or `auth.key` from the serialized
  output to prevent credential leakage through the API.

### ManagerAPI
- Add `ensurePdModeEnabled()` guard to all PD-specific endpoints
  (`createManager`, `deleteManager`, `list`, `checkRole`, `getRolesInGs`,
  `checkDefaultRole`).
- Wrap `HugeDefaultRole.valueOf()` in try-catch to return HTTP 400 instead
  of HTTP 500 when an invalid role string is supplied.

### SchemaTemplateAPI
- Fix incorrect `HugeException` import; replace with `ForbiddenException`
  for proper HTTP 403 semantics.
- Add missing `@RolesAllowed` annotations and implement `checkUpdate()`
  validation.

### StandardAuthManager
- Implement `setDefaultGraph` / `getDefaultGraph` / `unsetDefaultGraph`
  using marker-group pattern (HugeGroup + HugeBelong) for persistence.
- Implement `createDefaultRole` / `createSpaceDefaultRole` /
  `isDefaultRole` / `deleteDefaultRole` with the same marker-group
  mechanism.
- Add detailed design-note Javadoc explaining the workaround, its
  limitations, and the non-PD degradation path.

## Code quality improvements

- Extract shared `isPrefix(Map, String)` helper and `DATE_FORMATTER`
  constant into the `API` base class, eliminating ~30 lines of duplicated
  code across `GraphsAPI` and `GraphSpaceAPI`.
- Replace non-thread-safe `SimpleDateFormat` (constructed per-request) with
  a single static `DateTimeFormatter` (immutable, thread-safe).
- Fix 12-hour clock format `hh` → 24-hour `HH` in `GraphSpaceAPI`.
…raphs

from PD

Previously, HugeGremlinServer was started after HugeRestServer, causing
ContextGremlinServer's GRAPH_CREATE listener to be registered too late.
Graphs loaded from PD/meta during RestServer initialization fired their
GRAPH_CREATE events before the listener existed, so they were never
injected into Gremlin's global bindings. This caused:

"Could not rebind [g] to [__g_DEFAULT-xx] as [__g_DEFAULT-xx] not in
the Graph or TraversalSource global bindings" (HTTP 400)

Fix: split HugeGremlinServer.start() into prepare() + startPrepared().
prepare() constructs ContextGremlinServer (registering listeners) before
RestServer starts. startPrepared() is called after RestServer finishes
loading graphs. This ensures all PD-loaded graphs are captured by the
listener and injected correctly.

Affected files:

- HugeGraphServer: call prepare() before RestServer, startPrepared() after
- HugeGremlinServer: add prepare()/startPrepared(), keep start() for compat
- ContextGremlinServer: no behavioral change (listeners register on construct)
…ethods

Root Cause:
In StandardAuthManagerV2, the `createUser` (and other create methods: `createGroup`, `createTarget`, `createBelong`, `createAccess`) only initialized timestamps but failed to call `updateCreator()`. During serialization, `SchemaDefine.AuthElement.asMap` enforces a strict `creator != null` validation, resulting in an `IllegalStateException`.

Changes:
- Added `updateCreator(xxx)` calls immediately after `xxx.create(xxx.update())` in all 5 `create*` methods.
- Hardened the `updateCreator` method: Introduced a fallback to "system" when `currentUsername()` returns null. This ensures the `creator` is always populated, preventing errors during system initialization when no HTTP context is available.
Add the private static isPrefix() method that was accidentally removed
in a previous commit. This method is used by listProfile() to filter
graphs by name or nickname prefix, with proper null handling for
nickname field.

This fixes a compilation error where isPrefix() was called but not
defined.
Check if belong record exists before attempting to delete in
unsetDefaultGraph() to prevent throwing exceptions when unsetting
an already-unset default graph. This makes the API idempotent and
prevents 500 errors when clients call unset multiple times.

The fix aligns StandardAuthManagerV2 with StandardAuthManager, which
already implements this idempotent behavior.
- SchemaTemplateAPI: add ensurePdModeEnabled() guard to all endpoints
  to prevent NPE when MetaManager is not initialized in standalone mode
- SchemaTemplateAPI: add null body check in create() and update() to
  return 400 instead of NPE/500 on missing request body
- GraphsAPI.listProfile: format default_update_time consistently with
  create_time using DATE_FORMATTER instead of raw Date serialization
- GraphsAPI.manage: guard value.getClass() against null action value
  to prevent NPE when building the validation error message
- GraphSpaceAPI.deleteDefaultRole: wrap HugeDefaultRole.valueOf() in
  try/catch to return 400 for invalid role values instead of 500
- GraphManager: add isPDEnabled() guard to all schema-template methods
  to prevent NPE when MetaManager is not available in standalone mode
- GraphManager.updateGraphNickname: propagate PD persistence failure to
  caller with in-memory rollback, preventing silent state inconsistency
- GraphsAPI: remove duplicate private isPrefix() that shadowed the
  protected version in API base class, causing compilation failure
- GraphsAPI: fix NPE in manage() when 'update' value is null by
  guarding value.getClass() in both action and update validation
- GraphsAPI/GraphSpaceAPI: replace org.apache.commons.lang.StringUtils
  with commons-lang3 and remove org.apache.logging.log4j.util.Strings
  import (replaced with StringUtils equivalents) to fix potential
  classpath issues
- GraphManager.updateGraphNickname: restore old nickname (not null)
  on PD persistence failure to avoid a third inconsistent state
- StandardAuthManagerV2.setDefaultGraph: check existBelong() before
  createBelong() to make the operation idempotent; repeated POST calls
  for the same user/graph no longer throw HugeException
- StandardAuthManagerV2.createDefaultRole: same idempotent guard via
  existBelong() check before createBelong()
- ManagerAPI.checkDefaultRole: use @PathParam graphspace instead of
  @QueryParam to match the mounted path contract
StandardAuthManager (standalone RocksDB) fully implements setDefaultGraph/
unsetDefaultGraph/getDefaultGraph via HugeGroup+HugeBelong mechanism and
does not require PD. The non-PD early-return guards in setDefault, unsetDefault,
getDefault and listProfile were silently discarding user preferences, making
the API a no-op in standalone mode.

Remove the isPDEnabled() short-circuits and route all default graph operations
directly through authManager, which dispatches correctly to either
StandardAuthManager or StandardAuthManagerV2 depending on the deployment mode.
…nding

- Fix SchemaTemplateAPI logger using wrong class (RestServer -> SchemaTemplateAPI)
- Fix StandardAuthManager fabricated belong ID: replace string-constructed IDs
  with actual graph traversal (findBelongBinding) to correctly detect/delete
  existing HugeBelong edges, making setDefaultGraph/unsetDefaultGraph/
  createDefaultRole idempotent
- Fix HugeUser.initSchemaIfNeeded: add incremental schema upgrade so existing
  deployments get the user_nickname property key without full schema recreation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant