Skip to content

Commit 8ffdf5e

Browse files
authored
Merge pull request #4 from isa-group/develop
Develop
2 parents 7f24257 + 8b9419e commit 8ffdf5e

257 files changed

Lines changed: 108000 additions & 5909 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,4 +210,6 @@ __marimo__/
210210
node_modules/
211211
.venv/
212212
.env
213-
.envrc
213+
.envrc
214+
215+
.vscode

.vscode/settings.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

README.md

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,29 @@ OpenBinding is a QoS-aware service composition gateway and solver engine framewo
55
## 🏗️ Architecture
66

77
```mermaid
8-
graph TD
9-
User[User / Frontend] -->|HTTP POST /v1/solve| Gateway[OpenBinding Gateway]
10-
Gateway -->|1. Validate General Schema| Schema[General QoS Schema]
11-
Gateway -->|2. Validate Specialization| Spec[Specialization Schema]
12-
Gateway -->|3. Route Request| Router{Router}
13-
14-
Router -->|engine_id=minizinc-csp| MZ[MiniZinc CSP Engine]
15-
Router -->|engine_id=random-search| RS[Random Search Engine]
16-
17-
MZ -->|Solve via Gecode| Solution
18-
RS -->|Solve via Random Heuristic| Solution
19-
20-
Solution --> Gateway
21-
Gateway -->|HTTP 200| User
8+
flowchart TD
9+
U[User / Frontend]:::client
10+
11+
U -->|HTTP POST /v1/solve| G[OpenBinding Gateway]:::gateway
12+
13+
G --> V0[Validate request envelope]:::step
14+
V0 --> V1[Validate basic composition schema]:::schema
15+
V1 --> R{Root router: route by engine_id}:::router
16+
17+
R -->|minizinc-csp| SZ_MZ[Validate specialization schema: MiniZinc]:::schema
18+
R -->|random-search| SZ_RS[Validate specialization schema: Random Search]:::schema
19+
R -->|many-heuristic| SZ_MH[Validate specialization schema: Many-Heuristic]:::schema
20+
21+
SZ_MZ --> MZ[MiniZinc CSP engine]:::engine
22+
SZ_RS --> RS[Random Search engine]:::engine
23+
SZ_MH --> MH[Many-Heuristic engine]:::engine
24+
25+
MZ -->|solve| SOL[(Solution)]:::solution
26+
RS -->|solve| SOL
27+
MH -->|solve| SOL
28+
29+
SOL --> G
30+
G -->|HTTP 200 result| U
2231
```
2332

2433
## 🧩 Components
@@ -40,6 +49,11 @@ graph TD
4049
* Uses random search.
4150
* Best for exploring large solution spaces.
4251

52+
4. **Many-Heuristic Engine** (`engines/many-heuristic`):
53+
* Java service (extends Random Search).
54+
* Specialized for **Many-Objective** problems (3+ objectives).
55+
* Returns a **Pareto front** of non-dominated solutions.
56+
4357
4. **Frontend** (`frontend`):
4458
* React + Vite web UI for modeling and submitting problems.
4559
* Multi-page SPA with professional design inspired by modern developer tools.
@@ -56,6 +70,7 @@ OpenBinding validates incoming requests against two schema layers:
5670

5771
1. **General schema** (engine-agnostic):
5872
- JSON Schema (structural validation): `schemas/general/schema.json`
73+
- Visual model (Mermaid): `schemas/general/schema.mermaid`
5974
- Specification / semantics (human-readable): `schemas/general/schema.specification.md`
6075

6176
The specification document explains the intent and semantics behind the JSON Schema, including:
@@ -67,6 +82,14 @@ OpenBinding validates incoming requests against two schema layers:
6782
2. **Specialization schemas** (engine-specific constraints):
6883
- `schemas/specializations/minizinc-csp.schema.json`
6984
- `schemas/specializations/random-search.schema.json`
85+
- `schemas/specializations/many-heuristic.schema.json`
86+
87+
Specializations can also include a visual model in Mermaid format (recommended):
88+
- `schemas/specializations/minizinc-csp.schema.mermaid`
89+
- `schemas/specializations/random-search.schema.mermaid`
90+
- `schemas/specializations/many-heuristic.schema.mermaid`
91+
92+
Mermaid models are used by the frontend **Schema Explorer** in the **Model** tab. If a specialization does not provide `.schema.mermaid`, the JSON schema workflow remains fully functional.
7093

7194
Example payloads that follow these schemas live in `examples/`.
7295

@@ -89,6 +112,7 @@ Example payloads that follow these schemas live in `examples/`.
89112
* **Gateway API**: [http://localhost:8000/docs](http://localhost:8000/docs)
90113
* **MiniZinc Engine**: Port 3000 (Internal)
91114
* **Random Search Engine**: Port 8081 (Internal)
115+
* **Many-Heuristic Engine**: Port 8082 (Internal)
92116

93117
2. **Stop the Stack**:
94118
```bash
@@ -198,6 +222,14 @@ curl -X POST "http://localhost:8000/v1/solve" \
198222

199223
See `examples/` directory for sample payloads.
200224

225+
## 🧭 Engine Integration Guide
226+
227+
If you are adding a new engine, see [docs/ENGINE_INTEGRATION_GUIDE.md](docs/ENGINE_INTEGRATION_GUIDE.md).
228+
229+
## 🤝 Contributing
230+
231+
See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for branch and PR rules.
232+
201233
## 📄 License
202234

203235
This project is licensed under the **Creative Commons Attribution 4.0 International (CC BY 4.0)**.

docker-compose.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ services:
1515
- PYTHONPATH=/app/src
1616
- ENGINE_MINIZINC_URL=http://engine-minizinc:3000
1717
- ENGINE_RANDOM_SEARCH_URL=http://engine-random-search:8080
18+
- ENGINE_MANY_HEURISTIC_URL=http://engine-many-heuristic:8080
1819
healthcheck:
1920
test: ["CMD", "curl", "-fsS", "http://localhost:8000/health"]
2021
interval: 10s
@@ -26,6 +27,8 @@ services:
2627
condition: service_healthy
2728
engine-random-search:
2829
condition: service_healthy
30+
engine-many-heuristic:
31+
condition: service_healthy
2932

3033
engine-minizinc:
3134
build:
@@ -53,6 +56,19 @@ services:
5356
retries: 5
5457
start_period: 30s
5558

59+
engine-many-heuristic:
60+
build:
61+
context: ./engines/many-heuristic
62+
dockerfile: Dockerfile
63+
ports:
64+
- "8082:8080"
65+
healthcheck:
66+
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
67+
interval: 10s
68+
timeout: 3s
69+
retries: 5
70+
start_period: 30s
71+
5672
frontend:
5773
build:
5874
context: ./frontend
@@ -64,3 +80,9 @@ services:
6480
depends_on:
6581
gateway:
6682
condition: service_healthy
83+
healthcheck:
84+
test: ["CMD", "curl", "-fsS", "http://localhost/"]
85+
interval: 30s
86+
timeout: 5s
87+
retries: 3
88+
start_period: 10s

docs/CONTRIBUTING.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Contributing
2+
3+
Thanks for contributing to OpenBinding.
4+
5+
## Branching model
6+
7+
- Default branches: `develop` and `main`.
8+
- Always create new branches from `develop`.
9+
- Open pull requests into `develop`.
10+
- Admin will merge `develop` into `main` when appropriate.
11+
12+
## Workflow
13+
14+
1. Create a feature branch from `develop`:
15+
16+
```bash
17+
git checkout develop
18+
git pull
19+
git checkout -b feature/my-change
20+
```
21+
22+
2. Make changes with tests and documentation updates as needed.
23+
24+
3. Push the branch and open a PR targeting `develop`.
25+
26+
4. Address review feedback and keep the branch up to date with `develop`. All PRs must pass CI checks before merging.
27+
28+
## Expectations
29+
30+
- Keep changes focused and well tested.
31+
- Update docs when behavior changes.
32+
- Follow existing coding conventions and linting rules.
33+
- Document the rationale for non-trivial changes in the PR description. If possible, create a small video demo of the change in action.
34+
- Be responsive to review feedback and iterate on the PR until it meets the standards for merging. Each PR should be a self-contained unit of work that can be easily reviewed and understood.
35+
- All PRs must be reviewed and approved by at least one other contributor before merging. This ensures code quality and knowledge sharing across the team.

docs/ENGINE_INTEGRATION_GUIDE.md

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# Engine integration guide
2+
3+
This guide explains how to add a new engine to the OpenBinding gateway. It covers schema specialization, validation hooks, routing, and tests.
4+
5+
## Overview
6+
7+
The gateway validates incoming instances in stages and then routes them to the selected engine.
8+
9+
Validation stages:
10+
1. General schema
11+
2. Specialization schema
12+
3. General semantic rules
13+
4. Engine semantic rules
14+
15+
Engines integrate through the gateway plugin interface and a specialization schema.
16+
17+
## Required artifacts
18+
19+
1. Engine plugin (gateway): implement `EngineValidationPlugin`.
20+
2. Specialization schema: `schemas/specializations/<engine-id>.schema.json`.
21+
3. Specialization model (recommended): `schemas/specializations/<engine-id>.schema.mermaid`.
22+
4. Engine URL in registry + env wiring.
23+
5. Tests for validation and transformation.
24+
25+
## Step-by-step
26+
27+
### 1) Add a specialization schema
28+
29+
Create a specialization schema under `schemas/specializations/`.
30+
31+
### 1.1) Add a specialization model (recommended)
32+
33+
To enable visual exploration in the frontend **Schema Explorer** (`JSON | Model` tabs), add a Mermaid model next to your specialization schema:
34+
35+
- Path: `schemas/specializations/<engine-id>.schema.mermaid`
36+
- Naming must match your engine id exactly (`<engine-id>`)
37+
38+
The Mermaid model is optional, but strongly recommended for maintainability and onboarding.
39+
40+
If the file is missing, the frontend will show **Model not available** while keeping JSON schema validation and all engine workflows fully operational.
41+
42+
#### Good practices
43+
44+
- Keep JSON and Mermaid aligned conceptually (same constraints/capabilities).
45+
- Keep node/edge labels stable and meaningful across versions.
46+
- Prefer modular Mermaid subgraphs for large models.
47+
- Update both files in the same PR when constraints change.
48+
- Avoid changing `<engine-id>` naming once released, to prevent schema/model mismatch.
49+
50+
51+
## Engine options defaults (Playground)
52+
53+
The frontend Playground can prefill the `options` object depending on the selected engine.
54+
To support this, the gateway exposes engine-level defaults at:
55+
56+
- `GET /v1/engines/{engine_id}/options/defaults`
57+
58+
If the engine has no options, the endpoint returns an empty JSON object: `{}`.
59+
60+
### How to define defaults
61+
62+
Defaults are defined in the gateway engine plugin by implementing `get_default_options()`.
63+
Example:
64+
65+
- Return `{}` if your engine does not accept any options.
66+
- Return a JSON object with the gateway defaults (e.g. `{ "iterations_count": 1000 }`) if your engine supports options.
67+
68+
### 2) Implement the engine plugin
69+
70+
Create a new plugin in `openbinding-gateway/src/openbinding_gateway/validation/engine_plugins/`:
71+
72+
```python
73+
from typing import Any, Dict, List, Tuple
74+
import httpx
75+
from .base import EngineValidationPlugin
76+
from ...models.api import ValidationViolation
77+
78+
class MyEnginePlugin(EngineValidationPlugin):
79+
async def check_engine_health(self, base_url: str, client: httpx.AsyncClient) -> bool:
80+
resp = await client.get(f"{base_url.rstrip('/')}/health")
81+
return resp.status_code == 200
82+
83+
def get_capabilities(self) -> Dict[str, Any]:
84+
return {
85+
"qos_features_supported": ["*"],
86+
"composition_nodes_supported": ["TASK", "SEQ"],
87+
"objective_types_supported": ["weighted_sum"],
88+
"constraints_supported": ["attribute_bound"],
89+
"schema_version": "v1",
90+
}
91+
92+
def get_specialization_schema_path(self) -> str:
93+
# Uses SCHEMAS_DIR if available
94+
# e.g. /app/schemas/specializations/my-engine.schema.json
95+
...
96+
97+
def validate_semantics(self, instance: Dict[str, Any]) -> List[ValidationViolation]:
98+
violations: List[ValidationViolation] = []
99+
# Add engine-specific invariants here
100+
return violations
101+
102+
def transform_request(self, instance: Dict[str, Any], options: Dict[str, Any] = {}) -> Tuple[Dict[str, Any], List[str]]:
103+
# Map general instance to engine request payload
104+
return {"instance": instance, "options": options}, []
105+
106+
def transform_response(self, engine_response: Dict[str, Any], original_request: Dict[str, Any]) -> Dict[str, Any]:
107+
# Map engine response to gateway solution format
108+
return engine_response
109+
```
110+
111+
### 3) Register the plugin and URL
112+
113+
Add the plugin to `EngineRegistry`:
114+
115+
- File: `openbinding-gateway/src/openbinding_gateway/registry/engine.py`
116+
- Add env var for the engine URL (e.g. `ENGINE_MY_ENGINE_URL`).
117+
- Register the plugin in the initialization block.
118+
119+
Example:
120+
121+
```python
122+
from ..validation.engine_plugins.my_engine import MyEnginePlugin
123+
124+
_engine_urls = {
125+
"my-engine": os.getenv("ENGINE_MY_ENGINE_URL", "http://engine-my:1234"),
126+
}
127+
128+
EngineRegistry.register("my-engine", MyEnginePlugin())
129+
```
130+
131+
### 4) Ensure schema endpoints work
132+
133+
The gateway exposes:
134+
135+
- `/v1/schemas/general`
136+
- `/v1/schemas/general/model`
137+
- `/v1/schemas/<engine-id>`
138+
- `/v1/schemas/<engine-id>/model`
139+
140+
Your specialization schema must exist and be discoverable via `SCHEMAS_DIR`.
141+
Your specialization model should follow the same directory and naming convention to be discoverable by the `/model` endpoint.
142+
143+
### 5) Add tests
144+
145+
Recommended tests:
146+
147+
- Schema and semantic validation: `openbinding-gateway/tests/test_validation_comprehensive.py`
148+
- Plugin request/response transformation: `openbinding-gateway/tests/test_plugin_transformation.py`
149+
- Integration tests via docker compose (if the engine is available)
150+
151+
### 6) Wire docker compose (if needed)
152+
153+
Add the engine service to `docker-compose.yml` and expose the engine URL to the gateway:
154+
155+
```yaml
156+
environment:
157+
- ENGINE_MY_ENGINE_URL=http://engine-my:1234
158+
```
159+
160+
## Validation expectations
161+
162+
The gateway uses schema defaults and semantic checks before engine-specific validation. If your engine depends on implicit rules, enforce them in `validate_semantics`.
163+
164+
Common checks:
165+
166+
- Unsupported composition nodes
167+
- Unsupported constraint types or objective types
168+
- Missing candidates or missing QoS values
169+
- Attribute bounds on missing features
170+
171+
## Troubleshooting
172+
173+
- Check `/v1/engines` to confirm the engine is registered and reachable.
174+
- Use `/v1/analyze` for validation errors and warnings.
175+
- Ensure `SCHEMAS_DIR` resolves to the folder containing your specialization schema.
176+
- If the Model tab shows unavailable, confirm `<engine-id>.schema.mermaid` exists under `schemas/specializations/` and matches engine id naming exactly.

0 commit comments

Comments
 (0)