Repository navigation
Hyland OpenArch Integration
Issue / Pull Request: #170 / #175
Modules: oc-openarch-repository-connector, oc-openarch-output-connector (both bundled in oc-runtime)
Repository Connector Class: org.opencrawling.openarch.repository.OpenArchRepositoryConnector (OpenArch_Repository)
Output Connector Class: org.opencrawling.openarch.output.OpenArchOutputConnector (OpenArch_Output)
Decoupled Writer: org.opencrawling.openarch.output.messaging.OpenArchStoreWriterConsumer
Parquet Vector Bridge: org.opencrawling.openarch.output.parquet.OpenArchParquetEmbeddingsWriter
Security Mapper: org.opencrawling.openarch.output.security.OpenArchSecurityMapper
MCP Backend: org.opencrawling.runtime.mcp.backend.OpenArchMcpSearchBackend
OpenCrawling integrates with Hyland OpenArch in both directions. OpenArch is a cloud-native content and AI repository built on Spring Boot, MongoDB and OpenSearch. The integration has three parts:
-
Repository connector (
oc-openarch-repository-connector): Harvests documents, metadata, binaries and ACLs from OpenArch with paged HXQL queries (POST /api/query) and binary downloads (GET /api/download/{id}). It supports incremental filtering onsys_modifiedand fans out per-document work on Java 25 Virtual Threads (StructuredTaskScope). -
Output connector and Parquet vector bridge (
oc-openarch-output-connector): Uploads binaries (POST /api/upload) and upsertsSysFiledocuments (POST /api/documents/{parentId}) with mapped Zero-Trust ACLs. Embeddings are written as Apache Parquet files that follow OpenArch's Avro schema (embedding.avsc). -
Secure MCP backend (
OpenArchMcpSearchBackend): Plugs OpenArch intoMcpVectorServeras a search backend. It adds theopenarch_searchandopenarch_fetch_documentMCP tools and serves the standardsecureVectorSearch,getDocumentContentandlistAccessibleSourcestools.
The integration also adds Admin UI forms, catalogue defaults in ConnectorController, a connection check in ConnectorCheckerService, a new oc connector test alias, a decoupled Docker Compose stack and two integration test suites.
flowchart TD
subgraph OA["Hyland OpenArch"]
REST["REST API (/api/query, /api/query/embedding, /api/documents, /api/upload, /api/download)"]
Mongo[("MongoDB (SysFile, SysFolder, sys_acl)")]
OSearch[("OpenSearch (full-text and k-NN embeddings)")]
REST --> Mongo
REST --> OSearch
end
subgraph OC["OpenCrawling Runtime (Java 25)"]
RepoConn["OpenArchRepositoryConnector (paged HXQL + Virtual Threads)"]
OIS["OIS RepositoryDocument (UPSERT)"]
Kafka["Kafka topics (raw documents / opencrawling-embedded)"]
Ingest["oc-ingestion-consumer (Tika + chunking)"]
Embed["oc-embedding-consumer (Ollama mxbai-embed-large)"]
Writer["OpenArchStoreWriterConsumer (Parquet batching)"]
OutConn["OpenArchOutputConnector (upload + upsert + Parquet)"]
SecMap["OpenArchSecurityMapper (OIS to sys_acl)"]
Parquet["OpenArchParquetEmbeddingsWriter (embedding.avsc, SNAPPY)"]
Mcp["McpVectorServer + OpenArchMcpSearchBackend"]
end
Agent["AI Agent / LLM Client"]
REST -->|"POST /api/query, GET /api/download/{id}"| RepoConn
RepoConn --> OIS
OIS --> Kafka
Kafka --> Ingest
Ingest --> Embed
Embed -->|"opencrawling-embedded"| Writer
Writer --> Parquet
OutConn --> SecMap
OutConn --> Parquet
Parquet -->|"POST /api/upload (application/vnd.apache.parquet)"| REST
OutConn -->|"POST /api/upload, POST /api/documents/{parentId}"| REST
Agent <-->|"openarch_search / openarch_fetch_document"| Mcp
Mcp -->|"POST /api/query/embedding, GET /api/documents/{id}"| REST
All requests send Accept: application/json, the X-HXCS-Repository: <repositoryId> header and, when a username is configured, HTTP Basic authentication.
| Endpoint | Used by | Purpose |
|---|---|---|
POST /api/query |
Repository connector, MCP listAccessibleSources, connection check / ping |
Paged HXQL query (limit, offset, searchAfter) |
POST /api/query/embedding |
MCP backend | Vector + chunk full-text search over OpenArch embeddings |
GET /api/documents/{id} |
MCP getDocumentContent / openarch_fetch_document
|
Fetch document metadata |
POST /api/documents/{parentId}?upsert={true|false} |
Output connector | Create or update a SysFile document under the target folder |
POST /api/upload?fileName=…&mimeType=… |
Output connector, decoupled writer | Upload binaries and Parquet embedding files |
GET /api/download/{id} |
Repository connector | Stream the binary content of a document |
-
Paged HXQL harvesting: Runs
hxqlQuery(defaultSELECT * FROM SysFile) againstPOST /api/queryin pages ofbatchSizedocuments. It follows the server'snextSearchAftercursor if one is returned and falls back to offset paging otherwise. The crawl ends when a page is empty or smaller thanbatchSize. -
Java 25 Structured Concurrency:
scan()runs on a dedicated virtual thread (openarch-crawler-lane). Each page is mapped in parallel insideStructuredTaskScope.open(), and every task is wrapped inObservabilityTask.observed(...)so OpenTelemetry trace context propagates. The connector reportssupportsConcurrentProcessing() = true. -
Binary streaming: When
includeContentStream=true, the connector downloads each non-folder object (sys_primaryType != SysFolder) fromGET /api/download/{id}and attaches it as the document content stream, which then follows the normal Claim Check flow. Failed downloads are logged atDEBUGand the document is still emitted with its metadata. -
Incremental filtering: When
incremental=trueandlastCrawlTimestamp > 0(epoch milliseconds), the connector appendssys_modified >= '<ISO-8601>'to the query, usingANDif the query already has aWHEREclause andWHEREotherwise. -
Zero-Trust ACL preservation: Maps each
sys_aclentry to an OISPermissionRule. See ACL mapping. -
Schema introspection:
getSchema()exposes the OpenArch system fields (sys_id,sys_name,sys_title,sys_description,sys_primaryType,sys_mixinTypes,sys_path,sys_created,sys_modified,sys_acl,sys_effectivePermissions) for the Auto-Narrativization Copilot.
Warning
Current limitations (as of PR #175)
-
crawlMode,rootFolderIdandincludeSubfoldersare accepted by the configuration, the Admin UI and the connector catalogue, butscan()always runs the HXQL query path. Folder traversal (FOLDERmode) is not implemented yet. To limit a crawl to a folder, add a filter tohxqlQuery. - The
scan(basePath)argument (SCAN_PATH) is ignored. The query comes only fromhxqlQuery. - The connector emits only
UPSERTdocuments. Deletions in OpenArch do not produce OISDELETEtombstones. - If a document has no
sys_aclarray, orincludeAcls=false, it is emitted with a publicSecurityConfig.
Spring Property (spring.opencrawling.connector.openarch.*) |
connectors.json / Admin UI Key |
Default | Description |
|---|---|---|---|
endpoint-url |
endpointUrl |
http://localhost:8080 |
OpenArch REST API base URL |
repository-id |
repositoryId |
default |
Repository identifier sent as X-HXCS-Repository
|
username |
username |
Administrator |
Basic authentication username |
password |
password |
Administrator |
Basic authentication password |
crawl-mode |
crawlMode |
QUERY |
QUERY or FOLDER (see limitations above) |
hxql-query |
hxqlQuery |
SELECT * FROM SysFile |
HXQL query to harvest |
root-folder-id |
rootFolderId |
00000000-0000-0000-0000-000000000000 |
Root folder UUID for FOLDER mode (reserved) |
include-subfolders |
includeSubfolders |
true |
Recurse into child folders in FOLDER mode (reserved) |
batch-size |
batchSize |
100 |
Page size for HXQL pagination |
include-acls |
includeAcls |
true |
Map sys_acl to OIS permissions |
include-content-stream |
includeContentStream |
true |
Download binaries through /api/download/{id}
|
incremental |
incremental |
false |
Add a sys_modified filter to the query |
last-crawl-timestamp |
— | 0 |
Epoch milliseconds used as the lower bound when incremental=true
|
spring:
opencrawling:
repository-connector-type: openarch
crawl-on-startup: true
connector:
openarch:
endpoint-url: "https://openarch.enterprise.local"
repository-id: "default"
username: "crawler_service"
password: "${OPENARCH_PASSWORD}"
hxql-query: "SELECT * FROM SysFile WHERE sys_title LIKE '%.pdf'"
batch-size: 100
include-acls: true
include-content-stream: true
incremental: true
last-crawl-timestamp: 1767225600000 # 2026-01-01T00:00:00ZWith repository-connector-type: openarch, the runtime picks OpenArchRepositoryConnector because its class name contains openarch. If scan-path is empty, crawl-on-startup uses 00000000-0000-0000-0000-000000000000 as the default target and does not skip the crawl.
oc-crawler-openarch:
image: ghcr.io/opencrawling/oc-crawler:latest
environment:
- SPRING_KAFKA_BOOTSTRAP_SERVERS=kafka:9094
- SPRING_OPENCRAWLING_CRAWL_ON_STARTUP=true
- SPRING_OPENCRAWLING_REPOSITORY_CONNECTOR_TYPE=openarch
- SPRING_OPENCRAWLING_CONNECTOR_OPENARCH_ENDPOINT_URL=http://openarch:8080
- SPRING_OPENCRAWLING_CONNECTOR_OPENARCH_REPOSITORY_ID=default
- SPRING_OPENCRAWLING_CONNECTOR_OPENARCH_USERNAME=Administrator
- SPRING_OPENCRAWLING_CONNECTOR_OPENARCH_PASSWORD=Administrator
- SPRING_OPENCRAWLING_CONNECTOR_OPENARCH_HXQL_QUERY=SELECT * FROM SysFile
- SPRING_OPENCRAWLING_CONNECTOR_OPENARCH_BATCH_SIZE=100
- SPRING_OPENCRAWLING_CONNECTOR_OPENARCH_INCLUDE_ACLS=true| Metadata key | Value |
|---|---|
| every top-level field | Each non-null field of the OpenArch document is copied as-is (arrays become multi-valued lists), e.g. sys_name, sys_primaryType, sys_path, sys_modified, custom properties |
title |
sys_title, falling back to sys_name, then to the document ID |
description |
sys_description (if present) |
-
Document ID:
id, falling back tosys_id, then to a random UUID. -
URI:
openarch://<repositoryId>/<docId>. -
ACL reference:
openarch:acl:<docId>. -
Last modified:
sys_modifiedparsed as an ISO-8601 instant (or the current time if missing or unparsable).
{
"id": "7c1e2f8a-4b3d-4e5f-9a0b-1c2d3e4f5a6b",
"uri": "openarch://default/7c1e2f8a-4b3d-4e5f-9a0b-1c2d3e4f5a6b",
"action": "UPSERT",
"metadata": {
"sys_name": ["contract-2026-0042.pdf"],
"sys_primaryType": ["SysFile"],
"sys_mixinTypes": ["SysHasEmbeddings"],
"sys_modified": ["2026-10-20T09:15:00Z"],
"title": ["Master Services Agreement 2026"],
"description": ["Signed MSA with ACME Corp"]
},
"security": {
"inheritanceEnabled": true,
"permissions": [
{ "identity": "group:legal", "identityType": "group", "access": "read" },
{ "identity": "elena.weber", "identityType": "user", "access": "write" },
{ "identity": "restricted_user", "identityType": "user", "access": "deny" }
]
}
}The output connector is active when spring.opencrawling.output.type=openarch. OpenArchClientConfig then registers OpenArchOutputProperties and a shared OpenArchClient bean. On connect() the connector pings /api/query and logs a warning, without failing startup, if the ping does not succeed.
-
Binary upload: If
uploadBinaries=trueand the document has content, the content is uploaded toPOST /api/uploadwith themimeType/Content-Typemetadata (defaultapplication/octet-stream). If the upload fails, the connector logs a warning and continues with metadata only. -
SysFiledocument: Builds the OpenArch document:-
sys_primaryType: "SysFile",sys_name: <OIS id>,sys_title(fromtitleor the document ID) andsys_description(fromdescription). -
sys_modifiedandsys_createdfrom the OISlastModified. -
sys_mixinTypes: ["SysHasEmbeddings"]. -
file:content: { "data": <blobId>, "name": <OIS id> }when the binary upload succeeded. -
sys_aclmapped byOpenArchSecurityMapperwhensyncAcls=true. - All other OIS metadata keys that do not start with
sys_(single values become scalars, multiple values stay arrays).
-
-
Upsert:
POST /api/documents/{rootFolderId}?upsert={upsert}. Theidreturned by OpenArch becomes the target document ID. -
Parquet vector bridge: If an
ollamaEmbeddingModelbean is available and the document has content, the connector extracts the text with the Tika text extraction service, splits it withTokenTextSplitterand embeds each chunk. It then writes all chunks of the document to one SNAPPY-compressed Parquet file and uploads it asembeddings-<targetDocId>.parquet(application/vnd.apache.parquet). Chunk IDs are deterministic name-based UUIDs of<targetDocId>#<chunkIndex>, andblobrefpoints to the uploaded binary.
Note
DELETE tombstones: The output connector and the decoupled writer log DELETE actions ("OpenArch tombstone recorded") but do not yet delete anything in OpenArch. See Document Lifecycle Actions & Tombstones.
Spring Property (spring.opencrawling.output.openarch.*) |
connectors.json / Admin UI Key |
Default | Description |
|---|---|---|---|
endpoint-url |
endpointUrl |
http://localhost:8080 |
OpenArch REST API base URL |
repository-id |
repositoryId |
default |
Repository identifier (X-HXCS-Repository) |
username |
username |
Administrator |
Basic authentication username |
password |
password |
Administrator |
Basic authentication password |
root-folder-id |
rootFolderId |
00000000-0000-0000-0000-000000000000 |
Parent folder of ingested documents |
parquet-batch-threshold |
parquetBatchThreshold |
50 |
Number of chunks buffered by the decoupled writer before a Parquet file is flushed |
embeddings-type |
embeddingsType |
mxbai-embed-large |
Value written to the Parquet type column and used for MCP embedding queries |
dimensions |
dimensions |
1024 |
Vector dimensionality (used by the MCP backend) |
upsert |
upsert |
true |
Pass upsert=true to /api/documents/{parentId}
|
sync-acls |
syncAcls |
true |
Map OIS security to sys_acl
|
upload-binaries |
uploadBinaries |
true |
Upload binaries to /api/upload
|
spring:
opencrawling:
output:
type: openarch
openarch:
endpoint-url: "https://openarch.enterprise.local"
repository-id: "default"
username: "ingest_service"
password: "${OPENARCH_PASSWORD}"
root-folder-id: "00000000-0000-0000-0000-000000000000"
parquet-batch-threshold: 50
embeddings-type: "mxbai-embed-large"
dimensions: 1024
upsert: true
sync-acls: true
upload-binaries: trueOpenArchParquetEmbeddingsWriter loads /schemas/embedding.avsc (record com.hyland.openarch.embeddings.avro.Embedding) from the classpath and writes Parquet files with AvroParquetWriter and SNAPPY compression.
| Field | Type | Written value |
|---|---|---|
id |
string |
Chunk ID (random UUID if missing) |
type |
string |
embeddingsType (e.g. mxbai-embed-large) |
vector |
array<double> |
Embedding vector (float vectors are widened to double) |
text |
string |
Chunk text |
blobref |
["null", "string"] |
Uploaded binary ID (in-process connector) or source document ID (decoupled writer) |
location |
record Location |
text → TextLocation { page, paragraph } when page or paragraph is known; position { left, top, right, bottom }, timestamp { start, end } and spreadsheet { sheet, row, column } are written as null
|
In the decoupled Kafka pipeline, oc-writer-consumer writes the embeddings. OpenArchStoreWriterConsumer is active when both spring.opencrawling.output.type=openarch and opencrawling.consumer.writer.enabled=true are set. It:
- listens on the
opencrawling-embeddedtopic (DocumentEmbeddedMessage), - turns each chunk into an
EmbeddingChunk(id = chunkId,type = embeddingsType,blobref = documentId), - buffers chunks until
parquetBatchThresholdis reached, then writes one Parquet file and uploads it asembeddings-batch-<epochMillis>.parquet, - logs and skips
DELETEtombstones.
Tip
The decoupled compose stack sets SPRING_OPENCRAWLING_OUTPUT_OPENARCH_PARQUET_BATCH_THRESHOLD=1 so that every chunk is flushed immediately during tests. In production, raise the threshold so you upload fewer, larger Parquet files.
OpenArchSecurityMapper (output) and OpenArchRepositoryConnector (source) translate between OIS SecurityConfig and OpenArch sys_acl entries (ACEs).
OIS access
|
OpenArch ACE |
|---|---|
read |
{ "permission": "Read", "granted": true } |
write |
{ "permission": "Write", "granted": true } |
delete |
{ "permission": "Delete", "granted": true } |
admin |
{ "permission": "ManageSecurity", "granted": true } |
deny |
{ "permission": "Read", "granted": false } |
| anything else | { "permission": "Read", "granted": true } |
- An identity is treated as a group when
identityType=groupor the identity starts withgroup:orGROUP_. Groups become"group": { "groupname": … }with thegroup:prefix removed. All other identities become"user": { "username": … }with anyuser:prefix removed. - Every ACE is stamped with
"creator": "opencrawling".
OpenArch permission
|
OIS access
|
|---|---|
Read |
read |
Write, ReadWrite
|
write |
Delete, DeleteChild
|
delete |
ManageSecurity, ManageLock, All
|
admin |
any ACE with granted: false |
deny |
-
user.username(oruser.id) becomes auseridentity.group.groupname(orgroup.id) becomes agroup:<name>identity. A flatusernamefield is also accepted. - Mapped documents get
inheritanceEnabled: true.
When spring.opencrawling.output.type=openarch (and opencrawling.mcp.server.enabled is not false), OpenArchMcpSearchBackend (backendType() = "openarch") becomes the active McpVectorSearchBackend of McpVectorServer.
| Backend operation | OpenArch call | Behaviour |
|---|---|---|
secureVectorSearch |
POST /api/query/embedding |
Embeds the query with the ollamaEmbeddingModel (or openAiEmbeddingModel as fallback). Sends the vector, embeddingsType and the raw query as chunk full-text, then drops results below minScore
|
getDocumentContent |
GET /api/documents/{id} |
Strips the openarch://<repo>/ prefix and returns sys_title + sys_description as content, with all fields as metadata |
listAccessibleSources |
POST /api/query (SELECT * FROM SysFile, limit 50) |
Returns id, name (sys_name) and uri (openarch://<repo>/<id>) |
| MCP Tool | Parameters | Behaviour |
|---|---|---|
openarch_search |
query (string, required)userPrincipal (string, required)userRoles (string, optional, comma-separated)maxResults (int, optional)minScore (double, optional) |
Delegates to secureVectorSearch on the active backend |
openarch_fetch_document |
documentId (string, required): OpenArch ID or openarch:// URIuserPrincipal (string, required)userRoles (string, optional) |
Bare IDs are converted to openarch://default/<id>, then the call is delegated to getDocumentContent
|
Example JSON-RPC call:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "openarch_search",
"arguments": {
"query": "termination clauses in master services agreements",
"userPrincipal": "elena.weber",
"userRoles": "legal",
"maxResults": 5,
"minScore": 0.5
}
}
}Important
-
openarch_searchandopenarch_fetch_documentare always registered and run against the active backend, so they reach OpenArch only whenspring.opencrawling.output.type=openarch. - The MCP backend currently calls OpenArch with the configured service account (
spring.opencrawling.output.openarch.username), and every result is taggedopenarch:acl:read.userPrincipalanduserRolesare logged but are not forwarded to OpenArch or checked byMcpAclEvaluatorin this backend. Results are therefore limited to what the service account can see. Restrict that account accordingly until per-caller ACL filtering is added. -
openarch_fetch_documentassumes thedefaultrepository for bare IDs. For other repositories, pass a fullopenarch://<repositoryId>/<id>URI.
- Navigate to Connectors → New Connector.
- Choose one of:
-
Source: Hyland OpenArch Federated Repository (
org.opencrawling.openarch.repository.OpenArchRepositoryConnector). Fields: OpenArch Endpoint URL, Repository ID, Crawl Mode (QUERYshows HXQL Query,FOLDERshows Root Folder ID and Include Subfolders), Username, Password, Batch Size (Pages), and toggles for ACLs, content streams and incremental crawling. -
Output: Hyland OpenArch Federated Ingestion & Parquet Vector Bridge (
org.opencrawling.openarch.output.OpenArchOutputConnector). Fields: OpenArch Endpoint URL, Repository ID, Target Root Folder ID, Username, Password, Parquet Vector Batch Threshold, Embeddings Model Name / Type, Embedding Vector Dimensions, and toggles for upsert, ACL sync and binary upload.
-
Source: Hyland OpenArch Federated Repository (
- Click Test OpenArch Connectivity to run the server-side connection check.
The built-in connector catalogue now includes two entries with the defaults listed above:
| Name | Description | Type | Class |
|---|---|---|---|
OpenArch_Repository |
Hyland OpenArch Federated Repository | repository |
org.opencrawling.openarch.repository.OpenArchRepositoryConnector |
OpenArch_Output |
Hyland OpenArch Federated Ingestion & Parquet Vector Bridge | output |
org.opencrawling.openarch.output.OpenArchOutputConnector |
For any class name containing OpenArch / openarch, the checker sends POST <endpointUrl>/api/query with {"repositoryId": …, "query": "SELECT * FROM SysContent", "limit": 1}, the X-HXCS-Repository header and Basic auth, with a 5-second timeout.
| Response | Result |
|---|---|
2xx |
✅ "Successfully connected to Hyland OpenArch endpoint …" |
404 |
✅ "Hyland OpenArch server reachable … endpoint returned 404." |
| Other status / exception | ❌ Failure with the HTTP status or exception message |
endpointUrl falls back to url, then to http://localhost:8080, and a trailing / is removed.
PR #175 adds a test alias to oc connector check and lets you pass the connector name as a positional argument (see OpenCrawling CLI):
# Positional name + the new "test" alias
oc connector test OpenArch_Repository --type repository
# Classic form
oc connector check --name OpenArch_Output --type output
# Inline overrides of endpoint / credentials during the check
oc connector test OpenArch_Repository --type repository \
--config endpointUrl=http://openarch.internal:8080 \
--config username=crawler --config password=secretNote
--type still defaults to output, so add --type repository when you check OpenArch_Repository.
The decoupled stack is defined in oc-openarch-output-connector/docker/docker-compose-decoupled-with-openarch.yml. An identical copy lives in oc-openarch-repository-connector/docker/.
| Service | Container | Host ports | Role |
|---|---|---|---|
openarch |
openarch-decoupled |
${OPENARCH_PORT:-8081} → 8080, 5005 (debug) |
ghcr.io/hyland/openarch-app-jvm:${OPENARCH_VERSION:-latest} |
mongodb / mongodb-init
|
mongodb-openarch-decoupled |
27017 |
MongoDB 7 replica set rs0 (hostname mongo), initialized by a one-shot container |
opensearch |
opensearch-openarch-decoupled |
9200, 9600
|
OpenSearch 2.19 for OpenArch full-text and vector search |
redis |
redis-stack-decoupled-openarch |
6379, 8001
|
Redis Stack |
ollama / ollama-model-puller
|
ollama-decoupled-openarch |
11434 |
Ollama 0.40 with mxbai-embed-large
|
kafka |
kafka-decoupled-openarch |
9092 |
Apache Kafka 3.7 |
ozone-scm, ozone-om, ozone-datanode, ozone-s3g
|
ozone-*-openarch |
9878 (S3G) |
Apache Ozone 2.2.0 claim-check store |
oc-crawler |
oc-crawler-service-openarch |
— | Scans /data and publishes to Kafka (output.type=openarch) |
oc-ingestion-consumer |
oc-ingestion-consumer-service-openarch |
— | Tika (fork mode) parsing and chunking |
oc-embedding-consumer |
oc-embedding-consumer-service-openarch |
8082 |
Ollama embedding generation |
oc-writer-consumer |
oc-writer-service-openarch |
— |
OpenArchStoreWriterConsumer Parquet vector bridge |
oc-mcp-server |
oc-mcp-server-service-openarch |
${MCP_PORT:-8080}, 9095
|
Secure MCP Server backed by OpenArchMcpSearchBackend
|
docker compose -f oc-openarch-output-connector/docker/docker-compose-decoupled-with-openarch.yml up -dAll CI and local Dockerfiles (docker/Dockerfile.* and docker/local/Dockerfile.*) now copy both OpenArch modules. See Local Development & Fast Docker Builds.
mvn test -pl oc-openarch-output-connector,oc-openarch-repository-connector,oc-runtime -am| Test class | Module | Coverage |
|---|---|---|
OpenArchOutputConnectorTest |
output | Binary upload, SysFile upsert, ACL sync, Parquet upload |
OpenArchOutputConnectorActivationTest |
output | Conditional bean activation on output.type=openarch
|
OpenArchParquetEmbeddingsWriterTest |
output | Avro record creation and Parquet round-trip against embedding.avsc
|
OpenArchSecurityMapperTest |
output | OIS ↔ sys_acl mapping, deny handling, user/group detection |
OpenArchStoreWriterConsumerTest |
output | Kafka chunk buffering, threshold flush, DELETE tombstone handling |
OpenArchRepositoryConnectorTest |
repository | Paged HXQL, binary streaming, metadata and ACL mapping |
OpenArchMcpSearchBackendTest |
runtime | MCP search, fetch and source listing |
ConnectorCheckerServiceOpenArchTest |
runtime | Connection check outcomes |
OpenCrawlingCliTest#testConnectorTestCommandHelpAndAlias |
cli |
oc connector test --help alias |
./scripts/test-openarch-integration.shChecks for curl, jq and mvn and probes ${OPENARCH_URL:-http://localhost:8080}/api/status for a live instance. It then runs the Maven test suites of the three OpenArch-related modules.
./scripts/test-openarch-decoupled.shAn 11-step suite: prerequisites → cleanup of ports 8080 8081 9200 9092 6379 11434 27017 9878 → image build → infrastructure startup (MongoDB, OpenSearch, Redis, Ollama, OpenArch) → direct /api/upload + /api/documents ingestion with ACLs → oc-crawler scan and Kafka publication → OpenArchStoreWriterConsumer verification → paged HXQL harvesting → MCP readiness (openarch_search, openarch_fetch_document) → OIS DELETE tombstone → full *OpenArch* Maven suite.
If Docker is not available, the script builds with Maven and runs the MockWebServer / Parquet Avro test harness instead.
| Variable | Default | Description |
|---|---|---|
OPENARCH_HOST / OPENARCH_PORT
|
localhost / 8081
|
Host and port of the OpenArch container |
OPENARCH_URL |
http://${OPENARCH_HOST}:${OPENARCH_PORT} |
OpenArch base URL |
OPENARCH_USERNAME / OPENARCH_PASSWORD
|
Administrator / Administrator
|
Basic auth credentials |
OPENARCH_REPOSITORY_ID |
default |
Repository ID |
OPENARCH_ROOT_FOLDER_ID |
00000000-0000-0000-0000-000000000000 |
Target folder |
MCP_PORT |
8080 |
MCP server host port |
TIMEOUT |
300 |
Startup timeout (seconds) |
KEEP_CONTAINERS |
false |
Skip docker compose down on exit |
Both suites run in .github/workflows/integration-tests.yml as "Hyland OpenArch Integration Test Suite" (test-openarch-integration.sh) and "Hyland OpenArch Decoupled Pipeline Test Suite" (test-openarch-decoupled.sh). See Integration Test — Decoupled Pipeline.
- Home
- User & Installation Guide
- Quick Start
- VM & Bare-Metal Distribution Installation
- Local Development & Fast Docker Builds
- User Guide
- Architecture
- Zero-Trust Security & ACL Management
- Document Lifecycle Actions & Tombstones
- Apache Tika 4 Text Extraction
- Configuration Guide
- Connectors Reference
- Alfresco Content Services (ACS) Connector
- Alfresco Process Services (APS) Connector
- Flowable Repository Connector
- Camunda Repository Connector
- OASIS CMIS Repository Connector
- Doxis Repository Connector
- M-Files Repository Connector
- SharePoint Online Repository Connector
- Hyland OpenArch Integration (Repository, Output & MCP)
- Relational Database (JDBC) Connector
- Apache StormCrawler Repository Connector
- gRPC Push Repository Connector
- Apache Solr Output Connector
- Luxir Output Connector
- Apache SeaTunnel Output Connector
- Apache Ozone Output Connector (Migration Mode)
- Connector Execution Modes
- Model Context Protocol
- Apache Ozone Claim Check Store
- Lakehouse Audit Reporting & Ledger
- AI-Powered Observability (AIOps)
- Auto-Narrativization Copilot
- Maven Connector Archetypes
- Java Client SDK
- OpenCrawling CLI
- OpenAPI Specification & Swagger UI
- gRPC Internal Transport
- Migration Guide (ManifoldCF)
- Integration Test — Decoupled Pipeline
- M-Files Integration Test
- SharePoint Online Integration Test
- Hyland OpenArch Integration Test
- Local Docker Build Test
- Secure MCP Server Integration Test
- Narrativization Integration Test
- Reporting Integration Test