@mostajs/orm 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bridge/MostaJdbcBridge.java +345 -0
- package/dist/bridge/BridgeManager.d.ts +74 -0
- package/dist/bridge/BridgeManager.js +361 -0
- package/dist/bridge/JdbcNormalizer.d.ts +63 -0
- package/dist/bridge/JdbcNormalizer.js +253 -0
- package/dist/bridge/jdbc-registry.d.ts +31 -0
- package/dist/bridge/jdbc-registry.js +67 -0
- package/dist/dialects/abstract-sql.dialect.d.ts +26 -4
- package/dist/dialects/abstract-sql.dialect.js +77 -3
- package/dist/dialects/db2.dialect.js +2 -2
- package/dist/dialects/hana.dialect.js +2 -2
- package/dist/dialects/hsqldb.dialect.js +22 -56
- package/dist/dialects/mariadb.dialect.js +2 -2
- package/dist/dialects/mssql.dialect.d.ts +2 -2
- package/dist/dialects/mssql.dialect.js +2 -2
- package/dist/dialects/mysql.dialect.d.ts +2 -2
- package/dist/dialects/mysql.dialect.js +2 -2
- package/dist/dialects/oracle.dialect.js +2 -2
- package/dist/dialects/postgres.dialect.d.ts +2 -2
- package/dist/dialects/postgres.dialect.js +2 -2
- package/dist/dialects/spanner.dialect.js +2 -2
- package/dist/dialects/sybase.dialect.js +2 -2
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/docs/audit-dialects-vs-hibernate.md +642 -0
- package/docs/jdbc-normalizer-study.md +843 -0
- package/docs/plan-session-factory-multi-bridge.md +1233 -0
- package/jar_files/hsqldb-2.7.2.jar +0 -0
- package/package.json +3 -1
|
@@ -0,0 +1,1233 @@
|
|
|
1
|
+
# Plan de dev : SessionMostaORMFactory + Multi-Bridge + Auto-Start
|
|
2
|
+
|
|
3
|
+
> Auteur : Dr Hamid MADANI drmdh@msn.com
|
|
4
|
+
> Date : 2026-03-08
|
|
5
|
+
> Projet : @mostajs/orm (mosta-orm)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Sommaire
|
|
10
|
+
|
|
11
|
+
1. [Analyse de l'existant](#1-analyse-de-lexistant)
|
|
12
|
+
2. [Schemas de connexion et comportement](#2-schemas-de-connexion-et-comportement)
|
|
13
|
+
3. [Renommage AbstractSqlDialect → SessionMostaORMFactory](#3-renommage)
|
|
14
|
+
4. [Multi-Bridge : plusieurs instances JDBC simultanees](#4-multi-bridge)
|
|
15
|
+
5. [Auto-Start controlable par .env](#5-auto-start)
|
|
16
|
+
6. [Protection contre boucles et processus orphelins](#6-protections)
|
|
17
|
+
7. [Variables .env](#7-variables-env)
|
|
18
|
+
8. [Plan d'implementation](#8-plan-dimplementation)
|
|
19
|
+
9. [Matrice de risques](#9-matrice-de-risques)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Analyse de l'existant
|
|
24
|
+
|
|
25
|
+
### 1.1 Architecture actuelle
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
factory.ts (getDialect/createConnection)
|
|
29
|
+
│ singleton — UNE seule instance dialect a la fois
|
|
30
|
+
▼
|
|
31
|
+
AbstractSqlDialect (abstract-sql.dialect.ts)
|
|
32
|
+
│ - connect() avec interception JDBC bridge
|
|
33
|
+
│ - executeQuery() / executeRun() routage bridge ou natif
|
|
34
|
+
│ - UN seul JdbcNormalizer (1 bridge, 1 port)
|
|
35
|
+
▼
|
|
36
|
+
Dialect concret (oracle.dialect.ts, hsqldb.dialect.ts...)
|
|
37
|
+
│ - doConnect() / doExecuteQuery() / doExecuteRun()
|
|
38
|
+
│ - SQL pur (types, quotes, placeholders)
|
|
39
|
+
▼
|
|
40
|
+
MostaJdbcBridge.java
|
|
41
|
+
│ - UN seul processus Java sur port 8765
|
|
42
|
+
▼
|
|
43
|
+
SGBD cible
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 1.2 Problemes identifies
|
|
47
|
+
|
|
48
|
+
| # | Probleme | Detail |
|
|
49
|
+
|---|----------|--------|
|
|
50
|
+
| 1 | **Nom** | `AbstractSqlDialect` ne reflete pas son role de SessionFactory |
|
|
51
|
+
| 2 | **Mono-bridge** | Un seul bridge JDBC a la fois — impossible de connecter HSQLDB + Oracle simultanement |
|
|
52
|
+
| 3 | **Port fixe** | Port 8765 en dur — conflit si 2 bridges |
|
|
53
|
+
| 4 | **Auto-start non controlable** | Le bridge demarre toujours si JAR present — pas de choix |
|
|
54
|
+
| 5 | **Processus orphelins** | Si l'app crash, le process Java reste en memoire |
|
|
55
|
+
| 6 | **Boucle de demarrage** | Si le bridge echoue, il pourrait etre relance en boucle |
|
|
56
|
+
|
|
57
|
+
### 1.3 Mapping Hibernate
|
|
58
|
+
|
|
59
|
+
| Hibernate | @mostajs/orm actuel | @mostajs/orm propose |
|
|
60
|
+
|-----------|--------------------|--------------------|
|
|
61
|
+
| `Dialect` (SQL pur) | `AbstractSqlDialect` (SQL + connexion + bridge) | Dialect concret (SQL pur) |
|
|
62
|
+
| `SessionFactory` | `factory.ts` (getDialect) + `AbstractSqlDialect` (connect) | `SessionMostaORMFactory` |
|
|
63
|
+
| `ConnectionProvider` | Dans chaque dialect (doConnect) | Dans `SessionMostaORMFactory` (interception) |
|
|
64
|
+
| JDBC `DataSource` | `JdbcNormalizer` | `BridgeManager` (multi-instance) |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 2. Schemas de connexion et comportement
|
|
69
|
+
|
|
70
|
+
### 2.1 Schema global — Vue d'ensemble de l'architecture
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
┌─────────────────────────────────────────────────────────────────────────────────────────┐
|
|
74
|
+
│ APPLICATION (SecuAccessPro) │
|
|
75
|
+
│ │
|
|
76
|
+
│ .env.local : │
|
|
77
|
+
│ DB_DIALECT=hsqldb │
|
|
78
|
+
│ SGBD_URI=hsqldb:hsql://localhost:9001/mydb │
|
|
79
|
+
│ MOSTA_BRIDGE_AUTOSTART=true │
|
|
80
|
+
│ MOSTA_BRIDGE_PORT_INCREMENT=true │
|
|
81
|
+
└──────────────────────────────────┬──────────────────────────────────────────────────────┘
|
|
82
|
+
│
|
|
83
|
+
▼
|
|
84
|
+
┌─────────────────────────────────────────────────────────────────────────────────────────┐
|
|
85
|
+
│ factory.ts — createConnection() │
|
|
86
|
+
│ │
|
|
87
|
+
│ 1. Lit DB_DIALECT + SGBD_URI depuis .env │
|
|
88
|
+
│ 2. Charge le dialect : import('hsqldb.dialect.js') │
|
|
89
|
+
│ 3. Appelle dialect.connect(config) │
|
|
90
|
+
│ │
|
|
91
|
+
│ ┌──────────────────────────────────────────────────────────────────────────────────┐ │
|
|
92
|
+
│ │ SessionMostaORMFactory.connect(config) │ │
|
|
93
|
+
│ │ │ │
|
|
94
|
+
│ │ ┌─ JAR detecte dans jar_files/ ? │ │
|
|
95
|
+
│ │ │ │ │
|
|
96
|
+
│ │ │ OUI ──┐ MOSTA_BRIDGE_AUTOSTART ? │ │
|
|
97
|
+
│ │ │ │ ├── true → BridgeManager.getOrCreate() │ │
|
|
98
|
+
│ │ │ │ ├── detect → Health check port → reutilise ou lance │ │
|
|
99
|
+
│ │ │ │ └── false → Erreur "Start bridge manually" │ │
|
|
100
|
+
│ │ │ │ │ │
|
|
101
|
+
│ │ │ NON ──┘──── doConnect() du dialect (driver npm) │ │
|
|
102
|
+
│ │ │ ex: import('oracledb') → createPool() │ │
|
|
103
|
+
│ │ │ │ │
|
|
104
|
+
│ │ │ executeQuery(sql, params) / executeRun(sql, params) │ │
|
|
105
|
+
│ │ │ ├── Bridge actif ? → HTTP POST vers BridgeManager │ │
|
|
106
|
+
│ │ │ └── Bridge inactif ? → doExecuteQuery() du dialect │ │
|
|
107
|
+
│ │ └──────────────────────────────────────────────────────────────────────────────┘ │
|
|
108
|
+
└──────────────────────────────────┬──────────────────────────────────────────────────────┘
|
|
109
|
+
│
|
|
110
|
+
▼
|
|
111
|
+
┌─────────────────────────────────────────────────────────────────────────────────────────┐
|
|
112
|
+
│ BridgeManager (singleton global) │
|
|
113
|
+
│ │
|
|
114
|
+
│ bridges: Map<cle, BridgeInstance> │
|
|
115
|
+
│ ┌──────────────────────────────────────────────────────────────────────────────────┐ │
|
|
116
|
+
│ │ │ │
|
|
117
|
+
│ │ Cle Port PID JDBC URL │ │
|
|
118
|
+
│ │ ───────────────────────────── ───── ───── ─────────────────────────── │ │
|
|
119
|
+
│ │ hsqldb:localhost:9001/mydb 8765 14201 jdbc:hsqldb:hsql://... │ │
|
|
120
|
+
│ │ oracle:db.prod:1521/ORCLPDB1 8766 14305 jdbc:oracle:thin:@//... │ │
|
|
121
|
+
│ │ db2:srv:50000/MYDB 8767 14410 jdbc:db2://... │ │
|
|
122
|
+
│ │ │ │
|
|
123
|
+
│ │ nextPort: 8768 │ │
|
|
124
|
+
│ │ basePort: 8765 (MOSTA_BRIDGE_PORT_BASE) │ │
|
|
125
|
+
│ │ │ │
|
|
126
|
+
│ └──────────────────────────────────────────────────────────────────────────────────┘ │
|
|
127
|
+
│ │
|
|
128
|
+
│ Protections : │
|
|
129
|
+
│ ├── Anti-boucle : max 3 tentatives / 60s par cle │
|
|
130
|
+
│ ├── PID files : jar_files/.bridge-{port}.pid │
|
|
131
|
+
│ ├── Cleanup orphelins au demarrage │
|
|
132
|
+
│ └── process.on('exit') → stopAll() │
|
|
133
|
+
└───────────┬─────────────────────┬──────────────────────┬───────────────────────────────┘
|
|
134
|
+
│ │ │
|
|
135
|
+
▼ ▼ ▼
|
|
136
|
+
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
|
137
|
+
│ MostaJdbcBridge │ │ MostaJdbcBridge │ │ MostaJdbcBridge │
|
|
138
|
+
│ Java :8765 │ │ Java :8766 │ │ Java :8767 │
|
|
139
|
+
│ │ │ │ │ │
|
|
140
|
+
│ POST /query │ │ POST /query │ │ POST /query │
|
|
141
|
+
│ GET /health │ │ GET /health │ │ GET /health │
|
|
142
|
+
│ │ │ │ │ │
|
|
143
|
+
│ -cp hsqldb.jar │ │ -cp ojdbc11.jar │ │ -cp db2jcc4.jar │
|
|
144
|
+
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
|
|
145
|
+
│ JDBC │ JDBC │ JDBC
|
|
146
|
+
▼ ▼ ▼
|
|
147
|
+
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
|
|
148
|
+
│ HSQLDB │ │ Oracle DB │ │ IBM DB2 │
|
|
149
|
+
│ :9001 │ │ :1521 │ │ :50000 │
|
|
150
|
+
└──────────────────┘ └──────────────────┘ └──────────────────┘
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 2.2 Schema — Flux de connexion (decision tree)
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
connect(config) appele
|
|
157
|
+
│
|
|
158
|
+
▼
|
|
159
|
+
┌─────────────────────┐
|
|
160
|
+
│ Dialect dans │
|
|
161
|
+
│ JDBC_REGISTRY ? │
|
|
162
|
+
│ (hsqldb/oracle/ │
|
|
163
|
+
│ db2/sybase/hana) │
|
|
164
|
+
└──────┬──────────────┘
|
|
165
|
+
│
|
|
166
|
+
NON ─────────┤────────── OUI
|
|
167
|
+
│ │
|
|
168
|
+
▼ ▼
|
|
169
|
+
┌──────────────────┐ ┌──────────────────────┐
|
|
170
|
+
│ doConnect() │ │ JAR present dans │
|
|
171
|
+
│ du dialect │ │ jar_files/ ? │
|
|
172
|
+
│ │ └──────┬───────────────┘
|
|
173
|
+
│ import('pg') │ │
|
|
174
|
+
│ import('mysql2') │ NON ─────┤────────── OUI
|
|
175
|
+
│ import('mssql') │ │ │
|
|
176
|
+
│ etc. │ ▼ ▼
|
|
177
|
+
│ │ ┌──────────┐ ┌───────────────────────┐
|
|
178
|
+
│ npm driver natif │ │ doConnect│ │ MOSTA_BRIDGE_AUTOSTART│
|
|
179
|
+
└──────────────────┘ │ du │ │ = ? │
|
|
180
|
+
│ dialect │ └──────┬────────────────┘
|
|
181
|
+
│ (npm) │ │
|
|
182
|
+
│ │ ┌────┼────────┐
|
|
183
|
+
│ Si echec │ │ │ │
|
|
184
|
+
│ → erreur │ true detect false
|
|
185
|
+
│ "npm │ │ │ │
|
|
186
|
+
│ install" │ ▼ ▼ ▼
|
|
187
|
+
└──────────┘ ┌─────────┐ ┌──────────────────┐
|
|
188
|
+
│ Bridge │ │ doConnect() │
|
|
189
|
+
│ Manager │ │ du dialect (npm) │
|
|
190
|
+
│ .get │ │ │
|
|
191
|
+
│ Or │ │ Si echec : │
|
|
192
|
+
│ Create()│ │ "Start bridge │
|
|
193
|
+
└────┬────┘ │ manually or set │
|
|
194
|
+
│ │ AUTOSTART=true" │
|
|
195
|
+
▼ └──────────────────┘
|
|
196
|
+
┌──────────────────────┐
|
|
197
|
+
│ Bridge deja actif │
|
|
198
|
+
│ pour cette cle ? │
|
|
199
|
+
└──────┬───────────────┘
|
|
200
|
+
│
|
|
201
|
+
OUI ─────────┤────────── NON
|
|
202
|
+
│ │
|
|
203
|
+
▼ ▼
|
|
204
|
+
┌──────────────────┐ ┌──────────────────────┐
|
|
205
|
+
│ Reutiliser │ │ Port libre ? │
|
|
206
|
+
│ le bridge │ └──────┬───────────────┘
|
|
207
|
+
│ existant │ │
|
|
208
|
+
│ │ NON ─────┤────────── OUI
|
|
209
|
+
│ Pas de nouveau │ │ │
|
|
210
|
+
│ process Java │ ▼ ▼
|
|
211
|
+
└──────────────────┘ ┌──────────┐ ┌──────────────────┐
|
|
212
|
+
│ INCRE- │ │ Lancer │
|
|
213
|
+
│ MENT ? │ │ MostaJdbcBridge │
|
|
214
|
+
│ │ │ .java │
|
|
215
|
+
│ true: │ │ │
|
|
216
|
+
│ port++ │ │ java --source 11 │
|
|
217
|
+
│ │ │ -cp JAR bridge │
|
|
218
|
+
│ false: │ │ --port PORT │
|
|
219
|
+
│ ERREUR │ │ --jdbc-url URL │
|
|
220
|
+
│ "Port │ │ │
|
|
221
|
+
│ occupe" │ │ Ecrire PID file │
|
|
222
|
+
└──────────┘ │ Attendre health │
|
|
223
|
+
└────────┬─────────┘
|
|
224
|
+
│
|
|
225
|
+
▼
|
|
226
|
+
┌──────────────────────┐
|
|
227
|
+
│ Health check OK ? │
|
|
228
|
+
└──────┬───────────────┘
|
|
229
|
+
│
|
|
230
|
+
OUI ────────┤──────── NON
|
|
231
|
+
│ │
|
|
232
|
+
▼ ▼
|
|
233
|
+
┌──────────────────┐ ┌───────────────────┐
|
|
234
|
+
│ CONNECTE │ │ Tentative < 3 ? │
|
|
235
|
+
│ │ │ │
|
|
236
|
+
│ bridgeActive │ │ OUI → retry │
|
|
237
|
+
│ = true │ │ NON → ERREUR │
|
|
238
|
+
│ bridgeUrl │ │ "Bridge failed │
|
|
239
|
+
│ = http:// │ │ 3 times. Check │
|
|
240
|
+
│ localhost:PORT │ │ Java/JAR/SGBD" │
|
|
241
|
+
└──────────────────┘ └───────────────────┘
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 2.3 Schema — Execution des requetes (routage)
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
Application : dialect.find({ name: 'test' })
|
|
248
|
+
│
|
|
249
|
+
▼
|
|
250
|
+
SessionMostaORMFactory
|
|
251
|
+
├── translateFilter() → WHERE "name" = ?
|
|
252
|
+
├── buildSelectColumns() → SELECT "id", "name"...
|
|
253
|
+
├── buildOrderBy() → ORDER BY ...
|
|
254
|
+
└── buildLimitOffset() → LIMIT ... OFFSET ...
|
|
255
|
+
│
|
|
256
|
+
▼ SQL genere par le dialect
|
|
257
|
+
┌───────────────┐
|
|
258
|
+
│ executeQuery() │
|
|
259
|
+
└───────┬───────┘
|
|
260
|
+
│
|
|
261
|
+
┌──────────┴──────────┐
|
|
262
|
+
│ jdbcBridgeActive ? │
|
|
263
|
+
└──────────┬──────────┘
|
|
264
|
+
│
|
|
265
|
+
true ────────────┤──────────── false
|
|
266
|
+
│ │
|
|
267
|
+
▼ ▼
|
|
268
|
+
┌─────────────────────┐ ┌─────────────────────┐
|
|
269
|
+
│ bridgeExecuteQuery()│ │ doExecuteQuery() │
|
|
270
|
+
│ │ │ du dialect concret │
|
|
271
|
+
│ HTTP POST │ │ │
|
|
272
|
+
│ http://localhost: │ │ PostgreSQL: │
|
|
273
|
+
│ PORT/query │ │ pool.query(sql) │
|
|
274
|
+
│ │ │ │
|
|
275
|
+
│ Body: │ │ MySQL: │
|
|
276
|
+
│ { │ │ pool.execute(sql) │
|
|
277
|
+
│ "sql": "SELECT.." │ │ │
|
|
278
|
+
│ "params": [...] │ │ Oracle: │
|
|
279
|
+
│ } │ │ conn.execute(sql) │
|
|
280
|
+
└─────────┬───────────┘ └──────────┬──────────┘
|
|
281
|
+
│ │
|
|
282
|
+
▼ ▼
|
|
283
|
+
┌─────────────────────┐ ┌─────────────────────┐
|
|
284
|
+
│ MostaJdbcBridge │ │ Driver npm natif │
|
|
285
|
+
│ (Java) │ │ (pg/mysql2/mssql │
|
|
286
|
+
│ │ │ oracledb/ibm_db │
|
|
287
|
+
│ PreparedStatement │ │ @sap/hana-client) │
|
|
288
|
+
│ JDBC execute │ │ │
|
|
289
|
+
│ → JSON response │ │ Protocol natif │
|
|
290
|
+
└─────────┬───────────┘ └──────────┬──────────┘
|
|
291
|
+
│ │
|
|
292
|
+
▼ ▼
|
|
293
|
+
┌─────────────────────┐ ┌─────────────────────┐
|
|
294
|
+
│ SGBD via JDBC │ │ SGBD via protocol │
|
|
295
|
+
│ │ │ natif │
|
|
296
|
+
│ HSQLDB (HSQL) │ │ PostgreSQL (TCP) │
|
|
297
|
+
│ Oracle (TNS) │ │ MySQL (TCP) │
|
|
298
|
+
│ DB2 (DRDA) │ │ MongoDB (BSON) │
|
|
299
|
+
│ Sybase (TDS) │ │ SQLite (file) │
|
|
300
|
+
│ HANA (TCP) │ │ Spanner (gRPC) │
|
|
301
|
+
└─────────────────────┘ └─────────────────────┘
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 2.4 Schema — Cycle de vie des bridges
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
Demarrage Application
|
|
308
|
+
│
|
|
309
|
+
▼
|
|
310
|
+
┌─────────────────────────────────────────────────────────┐
|
|
311
|
+
│ BridgeManager.getInstance() │
|
|
312
|
+
│ │
|
|
313
|
+
│ 1. Lire fichiers PID : jar_files/.bridge-*.pid │
|
|
314
|
+
│ 2. Pour chaque PID : │
|
|
315
|
+
│ ├── Process vivant ? → Tuer (orphelin) │
|
|
316
|
+
│ └── Process mort ? → Supprimer fichier PID │
|
|
317
|
+
│ 3. Enregistrer handlers : │
|
|
318
|
+
│ ├── process.on('exit') → stopAll() │
|
|
319
|
+
│ ├── process.on('SIGINT') → stopAll() + exit │
|
|
320
|
+
│ └── process.on('SIGTERM') → stopAll() + exit │
|
|
321
|
+
└──────────────────────────┬──────────────────────────────┘
|
|
322
|
+
│
|
|
323
|
+
▼
|
|
324
|
+
┌──────────────── Vie de l'application ────────────────────┐
|
|
325
|
+
│ │
|
|
326
|
+
│ connect(hsqldb) ──┐ │
|
|
327
|
+
│ ▼ │
|
|
328
|
+
│ BridgeManager.getOrCreate('hsqldb:...') │
|
|
329
|
+
│ ├── Nouveau bridge → port 8765 │
|
|
330
|
+
│ └── Ecrire .bridge-8765.pid │
|
|
331
|
+
│ │
|
|
332
|
+
│ connect(oracle) ──┐ │
|
|
333
|
+
│ ▼ │
|
|
334
|
+
│ BridgeManager.getOrCreate('oracle:...') │
|
|
335
|
+
│ ├── Nouveau bridge → port 8766 │
|
|
336
|
+
│ └── Ecrire .bridge-8766.pid │
|
|
337
|
+
│ │
|
|
338
|
+
│ connect(hsqldb) ──┐ (meme cle que le 1er) │
|
|
339
|
+
│ ▼ │
|
|
340
|
+
│ BridgeManager.getOrCreate('hsqldb:...') │
|
|
341
|
+
│ └── Bridge existe deja → REUTILISER port 8765 │
|
|
342
|
+
│ (pas de nouveau process Java) │
|
|
343
|
+
│ │
|
|
344
|
+
│ disconnect(hsqldb) ──┐ │
|
|
345
|
+
│ ▼ │
|
|
346
|
+
│ Le bridge N'EST PAS arrete │
|
|
347
|
+
│ (d'autres connexions peuvent l'utiliser) │
|
|
348
|
+
│ bridgeActive = false sur CE dialect │
|
|
349
|
+
│ │
|
|
350
|
+
└──────────────────────────────────────────────────────────┘
|
|
351
|
+
│
|
|
352
|
+
▼
|
|
353
|
+
┌─────────────────────────────────────────────────────────┐
|
|
354
|
+
│ Arret Application (exit / SIGINT / SIGTERM / crash) │
|
|
355
|
+
│ │
|
|
356
|
+
│ BridgeManager.stopAll() │
|
|
357
|
+
│ ├── bridge hsqldb:8765 → kill(PID, SIGTERM) │
|
|
358
|
+
│ │ └── Supprimer .bridge-8765.pid │
|
|
359
|
+
│ ├── bridge oracle:8766 → kill(PID, SIGTERM) │
|
|
360
|
+
│ │ └── Supprimer .bridge-8766.pid │
|
|
361
|
+
│ └── bridges.clear() │
|
|
362
|
+
│ │
|
|
363
|
+
│ Si crash sans cleanup : │
|
|
364
|
+
│ ├── Fichiers .bridge-*.pid restent │
|
|
365
|
+
│ └── Au prochain demarrage → cleanupOrphans() les tue │
|
|
366
|
+
└─────────────────────────────────────────────────────────┘
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### 2.5 Schema — Messages d'erreur et diagnostics
|
|
370
|
+
|
|
371
|
+
```
|
|
372
|
+
┌──────────────────────────────────────────────────────────────────────────┐
|
|
373
|
+
│ ARBRE DES MESSAGES D'ERREUR │
|
|
374
|
+
└──────────────────────────────────────────────────────────────────────────┘
|
|
375
|
+
|
|
376
|
+
connect() appele
|
|
377
|
+
│
|
|
378
|
+
▼
|
|
379
|
+
JAR present ?
|
|
380
|
+
│
|
|
381
|
+
NON ─┤
|
|
382
|
+
│ Driver npm disponible ?
|
|
383
|
+
│ │
|
|
384
|
+
│ OUI → doConnect() → Succes ✓
|
|
385
|
+
│ │
|
|
386
|
+
│ NON → ╔════════════════════════════════════════════════════╗
|
|
387
|
+
│ ║ ERREUR: No driver found for {dialect}. ║
|
|
388
|
+
│ ║ Option 1: npm install {driver} ║
|
|
389
|
+
│ ║ Option 2: Place {jar}*.jar in jar_files/ ║
|
|
390
|
+
│ ║ and set MOSTA_BRIDGE_AUTOSTART=true ║
|
|
391
|
+
│ ╚════════════════════════════════════════════════════╝
|
|
392
|
+
│
|
|
393
|
+
OUI ─┤
|
|
394
|
+
▼
|
|
395
|
+
MOSTA_BRIDGE_AUTOSTART ?
|
|
396
|
+
│
|
|
397
|
+
false ┤── Driver npm disponible ?
|
|
398
|
+
│ │
|
|
399
|
+
│ OUI → doConnect() (npm) → Succes ✓
|
|
400
|
+
│ │
|
|
401
|
+
│ NON → ╔════════════════════════════════════════════════════╗
|
|
402
|
+
│ ║ ERREUR: JDBC bridge disabled. ║
|
|
403
|
+
│ ║ Start manually: ║
|
|
404
|
+
│ ║ java --source 11 -cp {jar} ║
|
|
405
|
+
│ ║ MostaJdbcBridge.java ║
|
|
406
|
+
│ ║ --jdbc-url {jdbcUrl} ║
|
|
407
|
+
│ ║ --port {port} ║
|
|
408
|
+
│ ║ Or set MOSTA_BRIDGE_AUTOSTART=true ║
|
|
409
|
+
│ ╚════════════════════════════════════════════════════╝
|
|
410
|
+
│
|
|
411
|
+
true/detect
|
|
412
|
+
│
|
|
413
|
+
▼
|
|
414
|
+
Java installe ?
|
|
415
|
+
│
|
|
416
|
+
NON ─┤── ╔════════════════════════════════════════════════════════╗
|
|
417
|
+
│ ║ ERREUR: Java 11+ required for JDBC bridge. ║
|
|
418
|
+
│ ║ Install: sudo apt install openjdk-11-jre ║
|
|
419
|
+
│ ║ Or: sudo apt install default-jre ║
|
|
420
|
+
│ ║ Verify: java --version ║
|
|
421
|
+
│ ╚════════════════════════════════════════════════════════╝
|
|
422
|
+
│
|
|
423
|
+
OUI ─┤
|
|
424
|
+
▼
|
|
425
|
+
Port libre ?
|
|
426
|
+
│
|
|
427
|
+
NON ─┤── INCREMENT active ?
|
|
428
|
+
│ │
|
|
429
|
+
│ OUI → port++ → retry
|
|
430
|
+
│ │
|
|
431
|
+
│ NON → ╔════════════════════════════════════════════════════╗
|
|
432
|
+
│ ║ ERREUR: Port {port} already in use. ║
|
|
433
|
+
│ ║ Set MOSTA_BRIDGE_PORT_INCREMENT=true ║
|
|
434
|
+
│ ║ Or change MOSTA_BRIDGE_PORT_BASE ║
|
|
435
|
+
│ ║ Or stop process using port {port}: ║
|
|
436
|
+
│ ║ lsof -i :{port} ║
|
|
437
|
+
│ ╚════════════════════════════════════════════════════╝
|
|
438
|
+
│
|
|
439
|
+
OUI ─┤
|
|
440
|
+
▼
|
|
441
|
+
Lancement bridge...
|
|
442
|
+
│
|
|
443
|
+
Health check OK ?
|
|
444
|
+
│
|
|
445
|
+
NON ─┤── Tentatives < MAX_RETRIES ?
|
|
446
|
+
│ │
|
|
447
|
+
│ OUI → retry (compteur++)
|
|
448
|
+
│ │
|
|
449
|
+
│ NON → ╔════════════════════════════════════════════════════╗
|
|
450
|
+
│ ║ ERREUR: JDBC bridge failed {n} times in 60s. ║
|
|
451
|
+
│ ║ Diagnostic: ║
|
|
452
|
+
│ ║ 1. Java installed? → java --version ║
|
|
453
|
+
│ ║ 2. JAR valid? → ls jar_files/{jar}*.jar ║
|
|
454
|
+
│ ║ 3. SGBD running? → check port {sgbdPort} ║
|
|
455
|
+
│ ║ 4. Firewall? → check port {bridgePort} ║
|
|
456
|
+
│ ║ 5. Bridge log: → stderr output above ║
|
|
457
|
+
│ ╚════════════════════════════════════════════════════╝
|
|
458
|
+
│
|
|
459
|
+
OUI ─┤
|
|
460
|
+
▼
|
|
461
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
462
|
+
║ SUCCES: Connected to {dialect} via JDBC bridge ║
|
|
463
|
+
║ Bridge: http://localhost:{port} ║
|
|
464
|
+
║ JDBC: {jdbcUrl} ║
|
|
465
|
+
║ PID: {pid} ║
|
|
466
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### 2.6 Schema — Comparaison driver npm vs JDBC bridge
|
|
470
|
+
|
|
471
|
+
```
|
|
472
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
473
|
+
│ CHEMIN A : Driver npm natif │
|
|
474
|
+
│ (postgres, mysql, mariadb, mssql, cockroachdb) │
|
|
475
|
+
│ │
|
|
476
|
+
│ SecuAccessPro │
|
|
477
|
+
│ │ │
|
|
478
|
+
│ ▼ │
|
|
479
|
+
│ SessionMostaORMFactory │
|
|
480
|
+
│ │ connect() │
|
|
481
|
+
│ ▼ │
|
|
482
|
+
│ doConnect() │
|
|
483
|
+
│ │ import('pg') │
|
|
484
|
+
│ ▼ │
|
|
485
|
+
│ ┌──────────┐ Protocol natif (TCP) ┌──────────────┐ │
|
|
486
|
+
│ │ npm │ ──────────────────────────── │ PostgreSQL │ │
|
|
487
|
+
│ │ driver │ │ Server │ │
|
|
488
|
+
│ │ (pg) │ Latence : ~0.1ms │ :5432 │ │
|
|
489
|
+
│ └──────────┘ └──────────────┘ │
|
|
490
|
+
│ │
|
|
491
|
+
│ Avantages : Direct, rapide, zero overhead │
|
|
492
|
+
│ Inconvenients : Depend de npm, parfois binaires C++ │
|
|
493
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
494
|
+
|
|
495
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
496
|
+
│ CHEMIN B : JDBC Bridge │
|
|
497
|
+
│ (hsqldb, oracle, db2, sybase, hana) │
|
|
498
|
+
│ │
|
|
499
|
+
│ SecuAccessPro │
|
|
500
|
+
│ │ │
|
|
501
|
+
│ ▼ │
|
|
502
|
+
│ SessionMostaORMFactory │
|
|
503
|
+
│ │ connect() │
|
|
504
|
+
│ ▼ │
|
|
505
|
+
│ BridgeManager.getOrCreate() │
|
|
506
|
+
│ │ │
|
|
507
|
+
│ ▼ │
|
|
508
|
+
│ ┌──────────┐ HTTP POST ┌──────────────┐ JDBC ┌─────────┐ │
|
|
509
|
+
│ │ Node.js │ ──────────── │ MostaJdbc │ ─────── │ Oracle │ │
|
|
510
|
+
│ │ fetch() │ localhost │ Bridge.java │ TCP │ Server │ │
|
|
511
|
+
│ │ │ :8765 │ │ :1521 │ │ │
|
|
512
|
+
│ └──────────┘ └──────────────┘ └─────────┘ │
|
|
513
|
+
│ │
|
|
514
|
+
│ Latence : ~1-2ms (HTTP localhost) │
|
|
515
|
+
│ Avantages : Zero npm binaire, driver officiel editeur (JDBC) │
|
|
516
|
+
│ Inconvenients : Process Java supplementaire │
|
|
517
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
518
|
+
|
|
519
|
+
┌─────────────────────────────────────────────────────────────────────┐
|
|
520
|
+
│ CHEMIN C : Pas de driver disponible │
|
|
521
|
+
│ (npm absent + JAR absent) │
|
|
522
|
+
│ │
|
|
523
|
+
│ SecuAccessPro │
|
|
524
|
+
│ │ │
|
|
525
|
+
│ ▼ │
|
|
526
|
+
│ SessionMostaORMFactory │
|
|
527
|
+
│ │ connect() │
|
|
528
|
+
│ ▼ │
|
|
529
|
+
│ ╔═══════════════════════════════════════════════════════════╗ │
|
|
530
|
+
│ ║ ERREUR ║ │
|
|
531
|
+
│ ║ ║ │
|
|
532
|
+
│ ║ No driver found for Oracle Database. ║ │
|
|
533
|
+
│ ║ ║ │
|
|
534
|
+
│ ║ Option 1 (npm): ║ │
|
|
535
|
+
│ ║ npm install oracledb ║ │
|
|
536
|
+
│ ║ ║ │
|
|
537
|
+
│ ║ Option 2 (JDBC bridge): ║ │
|
|
538
|
+
│ ║ 1. Download ojdbc11.jar from oracle.com ║ │
|
|
539
|
+
│ ║ 2. Place it in jar_files/ ║ │
|
|
540
|
+
│ ║ 3. Set MOSTA_BRIDGE_AUTOSTART=true in .env ║ │
|
|
541
|
+
│ ╚═══════════════════════════════════════════════════════════╝ │
|
|
542
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
### 2.7 Schema — Multi-bridge en action (exemple concret)
|
|
546
|
+
|
|
547
|
+
```
|
|
548
|
+
Scenario : Application qui migre des donnees HSQLDB → Oracle
|
|
549
|
+
|
|
550
|
+
.env.local :
|
|
551
|
+
MOSTA_BRIDGE_AUTOSTART=true
|
|
552
|
+
MOSTA_BRIDGE_PORT_BASE=8765
|
|
553
|
+
MOSTA_BRIDGE_PORT_INCREMENT=true
|
|
554
|
+
|
|
555
|
+
jar_files/ :
|
|
556
|
+
hsqldb-2.7.2.jar
|
|
557
|
+
ojdbc11.jar
|
|
558
|
+
|
|
559
|
+
┌───────────────────────────────────────────────────────────────────┐
|
|
560
|
+
│ Code application : │
|
|
561
|
+
│ │
|
|
562
|
+
│ // Connexion source (HSQLDB) │
|
|
563
|
+
│ const source = await createConnection({ │
|
|
564
|
+
│ dialect: 'hsqldb', │
|
|
565
|
+
│ uri: 'hsqldb:hsql://localhost:9001/legacy', │
|
|
566
|
+
│ }); │
|
|
567
|
+
│ → BridgeManager lance bridge sur port 8765 │
|
|
568
|
+
│ → PID 14201, hsqldb-2.7.2.jar │
|
|
569
|
+
│ │
|
|
570
|
+
│ // Connexion destination (Oracle) │
|
|
571
|
+
│ const dest = await createConnection({ │
|
|
572
|
+
│ dialect: 'oracle', │
|
|
573
|
+
│ uri: 'oracle://system:pwd@db.prod:1521/ORCLPDB1', │
|
|
574
|
+
│ }); │
|
|
575
|
+
│ → BridgeManager lance bridge sur port 8766 │
|
|
576
|
+
│ → PID 14305, ojdbc11.jar │
|
|
577
|
+
│ │
|
|
578
|
+
│ // Migration │
|
|
579
|
+
│ const clients = await source.find(ClientSchema, {}); │
|
|
580
|
+
│ // → HTTP POST localhost:8765/query │
|
|
581
|
+
│ // → SELECT * FROM clients │
|
|
582
|
+
│ │
|
|
583
|
+
│ for (const client of clients) { │
|
|
584
|
+
│ await dest.create(ClientSchema, client); │
|
|
585
|
+
│ // → HTTP POST localhost:8766/query │
|
|
586
|
+
│ // → INSERT INTO "clients" (...) VALUES (:1, :2, ...) │
|
|
587
|
+
│ } │
|
|
588
|
+
│ │
|
|
589
|
+
│ // Deconnexion │
|
|
590
|
+
│ await source.disconnect(); // bridge 8765 reste actif │
|
|
591
|
+
│ await dest.disconnect(); // bridge 8766 reste actif │
|
|
592
|
+
│ │
|
|
593
|
+
│ // A la sortie de l'app → BridgeManager.stopAll() │
|
|
594
|
+
│ // → kill 14201, kill 14305 │
|
|
595
|
+
│ // → supprimer .bridge-8765.pid, .bridge-8766.pid │
|
|
596
|
+
└───────────────────────────────────────────────────────────────────┘
|
|
597
|
+
|
|
598
|
+
Etat des ports pendant l'execution :
|
|
599
|
+
|
|
600
|
+
Port Process JDBC URL PID file
|
|
601
|
+
───── ────────────────── ──────────────────────────────── ──────────────────
|
|
602
|
+
8765 MostaJdbcBridge jdbc:hsqldb:hsql://localhost/ .bridge-8765.pid
|
|
603
|
+
8766 MostaJdbcBridge jdbc:oracle:thin:@//db.prod/ORC .bridge-8766.pid
|
|
604
|
+
9001 HSQLDB Server (natif) —
|
|
605
|
+
1521 Oracle Server (natif) —
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
---
|
|
609
|
+
|
|
610
|
+
## 3. Renommage AbstractSqlDialect → SessionMostaORMFactory
|
|
611
|
+
|
|
612
|
+
### 3.1 Justification
|
|
613
|
+
|
|
614
|
+
Dans Hibernate :
|
|
615
|
+
- `Dialect` = definition SQL pure (types, quotes, fonctions)
|
|
616
|
+
- `SessionFactory` = fabrique de sessions, gere le cycle de vie connexion
|
|
617
|
+
|
|
618
|
+
Notre `AbstractSqlDialect` fait les deux : SQL pur + connexion + bridge JDBC.
|
|
619
|
+
Le renommage reflete ce double role et aligne avec Hibernate.
|
|
620
|
+
|
|
621
|
+
### 2.2 Fichiers impactes
|
|
622
|
+
|
|
623
|
+
| Fichier | Modification |
|
|
624
|
+
|---------|-------------|
|
|
625
|
+
| `abstract-sql.dialect.ts` | Renommer la classe `AbstractSqlDialect` → `SessionMostaORMFactory` |
|
|
626
|
+
| | Renommer le fichier → `session-factory.ts` |
|
|
627
|
+
| `postgres.dialect.ts` | `extends SessionMostaORMFactory` |
|
|
628
|
+
| `mysql.dialect.ts` | `extends SessionMostaORMFactory` |
|
|
629
|
+
| `oracle.dialect.ts` | `extends SessionMostaORMFactory` |
|
|
630
|
+
| `mssql.dialect.ts` | `extends SessionMostaORMFactory` |
|
|
631
|
+
| `db2.dialect.ts` | `extends SessionMostaORMFactory` |
|
|
632
|
+
| `hana.dialect.ts` | `extends SessionMostaORMFactory` |
|
|
633
|
+
| `hsqldb.dialect.ts` | `extends SessionMostaORMFactory` |
|
|
634
|
+
| `spanner.dialect.ts` | `extends SessionMostaORMFactory` |
|
|
635
|
+
| `mariadb.dialect.ts` | Herite de MySQLDialect (pas de changement) |
|
|
636
|
+
| `cockroachdb.dialect.ts` | Herite de PostgresDialect (pas de changement) |
|
|
637
|
+
| `sybase.dialect.ts` | Herite de MSSQLDialect (pas de changement) |
|
|
638
|
+
| `JdbcNormalizer.ts` | Mettre a jour les commentaires |
|
|
639
|
+
| `index.ts` | Exporter `SessionMostaORMFactory` |
|
|
640
|
+
|
|
641
|
+
### 2.3 Retrocompatibilite
|
|
642
|
+
|
|
643
|
+
```typescript
|
|
644
|
+
// Dans session-factory.ts — alias pour retrocompatibilite
|
|
645
|
+
export { SessionMostaORMFactory as AbstractSqlDialect };
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
## 3. Multi-Bridge : plusieurs instances JDBC simultanees
|
|
651
|
+
|
|
652
|
+
### 3.1 Besoin
|
|
653
|
+
|
|
654
|
+
Pouvoir connecter simultanement :
|
|
655
|
+
- HSQLDB sur port 8765
|
|
656
|
+
- Oracle sur port 8766
|
|
657
|
+
- DB2 sur port 8767
|
|
658
|
+
|
|
659
|
+
Sans devoir arreter l'un pour demarrer l'autre.
|
|
660
|
+
|
|
661
|
+
### 3.2 Architecture proposee : BridgeManager (singleton global)
|
|
662
|
+
|
|
663
|
+
```
|
|
664
|
+
BridgeManager (singleton)
|
|
665
|
+
┌──────────────────────────────────────┐
|
|
666
|
+
│ bridges: Map<string, BridgeInstance> │
|
|
667
|
+
│ │
|
|
668
|
+
│ hsqldb:8765 → { process, url, pid } │
|
|
669
|
+
│ oracle:8766 → { process, url, pid } │
|
|
670
|
+
│ db2:8767 → { process, url, pid } │
|
|
671
|
+
│ │
|
|
672
|
+
│ nextPort: 8768 │
|
|
673
|
+
│ basePort: 8765 │
|
|
674
|
+
└──────────┬───────────────────────────┘
|
|
675
|
+
│
|
|
676
|
+
┌───────────────────────┼───────────────────────┐
|
|
677
|
+
▼ ▼ ▼
|
|
678
|
+
MostaJdbcBridge:8765 MostaJdbcBridge:8766 MostaJdbcBridge:8767
|
|
679
|
+
│ │ │
|
|
680
|
+
▼ ▼ ▼
|
|
681
|
+
HSQLDB :9001 Oracle :1521 DB2 :50000
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### 3.3 Cle d'identification d'un bridge
|
|
685
|
+
|
|
686
|
+
Chaque bridge est identifie par une cle unique :
|
|
687
|
+
|
|
688
|
+
```
|
|
689
|
+
cle = `${dialect}:${host}:${port}/${database}`
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
Exemples :
|
|
693
|
+
- `hsqldb:localhost:9001/` → bridge sur port 8765
|
|
694
|
+
- `oracle:db.prod:1521/ORCLPDB1` → bridge sur port 8766
|
|
695
|
+
- `hsqldb:localhost:9001/testdb` → bridge sur port 8767 (autre base)
|
|
696
|
+
|
|
697
|
+
Cela permet :
|
|
698
|
+
- Deux connexions HSQLDB vers des bases differentes
|
|
699
|
+
- Reutiliser un bridge existant si meme cle (pas de duplication)
|
|
700
|
+
|
|
701
|
+
### 3.4 Incrementation des ports
|
|
702
|
+
|
|
703
|
+
```
|
|
704
|
+
Mode 1 : MOSTA_BRIDGE_PORT_INCREMENT=true (defaut)
|
|
705
|
+
─────────────────────────────────────────────────────
|
|
706
|
+
1er bridge → port 8765 (MOSTA_BRIDGE_PORT_BASE)
|
|
707
|
+
2eme bridge → port 8766
|
|
708
|
+
3eme bridge → port 8767
|
|
709
|
+
...
|
|
710
|
+
|
|
711
|
+
Mode 2 : MOSTA_BRIDGE_PORT_INCREMENT=false
|
|
712
|
+
─────────────────────────────────────────────────────
|
|
713
|
+
Tous les bridges sur le meme port → ERREUR si 2eme bridge demande
|
|
714
|
+
Utile si un seul SGBD JDBC a la fois
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
### 3.5 BridgeManager API
|
|
718
|
+
|
|
719
|
+
```typescript
|
|
720
|
+
class BridgeManager {
|
|
721
|
+
// Singleton
|
|
722
|
+
private static instance: BridgeManager;
|
|
723
|
+
static getInstance(): BridgeManager;
|
|
724
|
+
|
|
725
|
+
// Etat
|
|
726
|
+
private bridges: Map<string, BridgeInstance>;
|
|
727
|
+
private nextPort: number;
|
|
728
|
+
|
|
729
|
+
// Obtenir ou creer un bridge pour un dialect/URI
|
|
730
|
+
// Si le bridge existe deja (meme cle) → le reutilise
|
|
731
|
+
// Si nouveau → lance un process Java sur le prochain port
|
|
732
|
+
async getOrCreate(dialect, uri, options?): Promise<BridgeInstance>;
|
|
733
|
+
|
|
734
|
+
// Arreter un bridge specifique
|
|
735
|
+
async stop(key: string): Promise<void>;
|
|
736
|
+
|
|
737
|
+
// Arreter TOUS les bridges (cleanup global)
|
|
738
|
+
async stopAll(): Promise<void>;
|
|
739
|
+
|
|
740
|
+
// Lister les bridges actifs
|
|
741
|
+
list(): BridgeInstance[];
|
|
742
|
+
|
|
743
|
+
// Verifier si un bridge existe pour cette cle
|
|
744
|
+
has(key: string): boolean;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
interface BridgeInstance {
|
|
748
|
+
key: string; // cle unique
|
|
749
|
+
dialect: DialectType;
|
|
750
|
+
port: number; // port HTTP du bridge
|
|
751
|
+
url: string; // http://localhost:port
|
|
752
|
+
pid: number; // PID du process Java
|
|
753
|
+
jdbcUrl: string; // URL JDBC utilisee
|
|
754
|
+
startedAt: Date;
|
|
755
|
+
process: ChildProcess;
|
|
756
|
+
}
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
### 3.6 Integration avec SessionMostaORMFactory
|
|
760
|
+
|
|
761
|
+
```typescript
|
|
762
|
+
// Dans SessionMostaORMFactory.connect() :
|
|
763
|
+
|
|
764
|
+
async connect(config: ConnectionConfig): Promise<void> {
|
|
765
|
+
// ...
|
|
766
|
+
if (hasJdbcDriver(this.dialectType) && JdbcNormalizer.isAvailable(...)) {
|
|
767
|
+
// Utilise le BridgeManager au lieu de creer un JdbcNormalizer directement
|
|
768
|
+
const manager = BridgeManager.getInstance();
|
|
769
|
+
this.bridgeInstance = await manager.getOrCreate(
|
|
770
|
+
this.dialectType,
|
|
771
|
+
config.uri,
|
|
772
|
+
{ jarDir, bridgeJavaFile }
|
|
773
|
+
);
|
|
774
|
+
this.jdbcBridgeActive = true;
|
|
775
|
+
}
|
|
776
|
+
// ...
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
async disconnect(): Promise<void> {
|
|
780
|
+
// NE PAS arreter le bridge — d'autres dialects peuvent l'utiliser
|
|
781
|
+
// Le bridge sera arrete par BridgeManager.stopAll() ou manuellement
|
|
782
|
+
this.jdbcBridgeActive = false;
|
|
783
|
+
this.bridgeInstance = null;
|
|
784
|
+
}
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
---
|
|
788
|
+
|
|
789
|
+
## 4. Auto-Start controlable par .env
|
|
790
|
+
|
|
791
|
+
### 4.1 Modes de fonctionnement
|
|
792
|
+
|
|
793
|
+
```
|
|
794
|
+
Mode 1 : MOSTA_BRIDGE_AUTOSTART=true (defaut si JAR present)
|
|
795
|
+
─────────────────────────────────────────────────────────────
|
|
796
|
+
SessionMostaORMFactory.connect() lance automatiquement le bridge
|
|
797
|
+
si un JAR JDBC est detecte pour le dialect.
|
|
798
|
+
|
|
799
|
+
Comportement actuel — aucun changement.
|
|
800
|
+
|
|
801
|
+
Mode 2 : MOSTA_BRIDGE_AUTOSTART=false
|
|
802
|
+
─────────────────────────────────────────────────────────────
|
|
803
|
+
Le bridge n'est JAMAIS lance automatiquement.
|
|
804
|
+
L'utilisateur doit :
|
|
805
|
+
a) Lancer le bridge manuellement :
|
|
806
|
+
java --source 11 -cp hsqldb.jar MostaJdbcBridge.java --jdbc-url ...
|
|
807
|
+
b) Ou utiliser le CLI :
|
|
808
|
+
npx mosta-bridge start --dialect hsqldb --port 8765
|
|
809
|
+
|
|
810
|
+
Le dialect tente de se connecter au bridge sur le port configure.
|
|
811
|
+
Si le bridge n'est pas la → erreur claire.
|
|
812
|
+
|
|
813
|
+
Mode 3 : MOSTA_BRIDGE_AUTOSTART=detect (nouveau)
|
|
814
|
+
─────────────────────────────────────────────────────────────
|
|
815
|
+
Avant de lancer un nouveau bridge :
|
|
816
|
+
1. Verifier si un bridge tourne deja sur le port
|
|
817
|
+
2. Si oui → le reutiliser (pas de nouveau process)
|
|
818
|
+
3. Si non → le lancer automatiquement
|
|
819
|
+
|
|
820
|
+
Evite les doublons apres un redemarrage de l'app.
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
### 4.2 Flux de decision au connect()
|
|
824
|
+
|
|
825
|
+
```
|
|
826
|
+
connect(config) appelé
|
|
827
|
+
│
|
|
828
|
+
▼
|
|
829
|
+
dialect est-il dans JDBC_REGISTRY ?
|
|
830
|
+
│
|
|
831
|
+
NON ─┤── ▶ doConnect() natif (npm driver)
|
|
832
|
+
│
|
|
833
|
+
OUI ─┤
|
|
834
|
+
▼
|
|
835
|
+
MOSTA_BRIDGE_AUTOSTART ?
|
|
836
|
+
│
|
|
837
|
+
false ─┤── ▶ doConnect() natif (npm driver)
|
|
838
|
+
│ Si echec ET JAR present :
|
|
839
|
+
│ → message "Set MOSTA_BRIDGE_AUTOSTART=true or start bridge manually"
|
|
840
|
+
│
|
|
841
|
+
true ──┤── ▶ BridgeManager.getOrCreate()
|
|
842
|
+
│ Lance un nouveau bridge si necessaire
|
|
843
|
+
│
|
|
844
|
+
detect ┤── ▶ Verifie si bridge deja sur le port
|
|
845
|
+
│
|
|
846
|
+
OUI ─┤── ▶ Reutilise le bridge existant
|
|
847
|
+
│
|
|
848
|
+
NON ─┤── ▶ Lance un nouveau bridge
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
### 4.3 Detection d'un bridge existant (mode detect)
|
|
852
|
+
|
|
853
|
+
```typescript
|
|
854
|
+
async function detectExistingBridge(port: number): Promise<boolean> {
|
|
855
|
+
try {
|
|
856
|
+
const res = await fetch(`http://localhost:${port}/health`, {
|
|
857
|
+
signal: AbortSignal.timeout(2000),
|
|
858
|
+
});
|
|
859
|
+
return res.ok;
|
|
860
|
+
} catch {
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
---
|
|
867
|
+
|
|
868
|
+
## 5. Protection contre boucles et processus orphelins
|
|
869
|
+
|
|
870
|
+
### 5.1 Protection anti-boucle
|
|
871
|
+
|
|
872
|
+
| Risque | Scenario | Protection |
|
|
873
|
+
|--------|----------|------------|
|
|
874
|
+
| Relance infinie | Bridge crash → connect() relance → crash → relance... | Compteur de tentatives : max 3, puis erreur fatale |
|
|
875
|
+
| Start simultane | 2 connect() en parallele lancent 2 bridges sur le meme port | Mutex/lock dans BridgeManager |
|
|
876
|
+
| Port occupe | Le port est pris par un autre process | Verifier avant de lancer, incrementer si occupe |
|
|
877
|
+
|
|
878
|
+
```typescript
|
|
879
|
+
// Dans BridgeManager :
|
|
880
|
+
|
|
881
|
+
private startAttempts: Map<string, { count: number; lastAttempt: Date }> = new Map();
|
|
882
|
+
private MAX_START_ATTEMPTS = 3;
|
|
883
|
+
private ATTEMPT_RESET_MS = 60_000; // reset compteur apres 1 minute
|
|
884
|
+
|
|
885
|
+
async getOrCreate(dialect, uri, options?): Promise<BridgeInstance> {
|
|
886
|
+
const key = this.buildKey(dialect, uri);
|
|
887
|
+
|
|
888
|
+
// Bridge deja actif ? → reutiliser
|
|
889
|
+
if (this.bridges.has(key)) {
|
|
890
|
+
const bridge = this.bridges.get(key)!;
|
|
891
|
+
// Verifier qu'il est encore vivant
|
|
892
|
+
if (await this.isAlive(bridge)) return bridge;
|
|
893
|
+
// Mort → nettoyer et relancer
|
|
894
|
+
this.bridges.delete(key);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// Protection anti-boucle
|
|
898
|
+
const attempts = this.startAttempts.get(key);
|
|
899
|
+
if (attempts) {
|
|
900
|
+
const elapsed = Date.now() - attempts.lastAttempt.getTime();
|
|
901
|
+
if (elapsed < this.ATTEMPT_RESET_MS && attempts.count >= this.MAX_START_ATTEMPTS) {
|
|
902
|
+
throw new Error(
|
|
903
|
+
`JDBC bridge for "${key}" failed ${this.MAX_START_ATTEMPTS} times ` +
|
|
904
|
+
`in the last ${this.ATTEMPT_RESET_MS / 1000}s. Giving up.\n` +
|
|
905
|
+
`Check Java installation, JAR file, and SGBD server.`
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
if (elapsed >= this.ATTEMPT_RESET_MS) {
|
|
909
|
+
this.startAttempts.delete(key); // Reset
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// Lancer le bridge
|
|
914
|
+
try {
|
|
915
|
+
const bridge = await this.startBridge(dialect, uri, options);
|
|
916
|
+
this.startAttempts.delete(key); // Succes → reset compteur
|
|
917
|
+
return bridge;
|
|
918
|
+
} catch (e) {
|
|
919
|
+
// Incrementer le compteur
|
|
920
|
+
const current = this.startAttempts.get(key) || { count: 0, lastAttempt: new Date() };
|
|
921
|
+
current.count++;
|
|
922
|
+
current.lastAttempt = new Date();
|
|
923
|
+
this.startAttempts.set(key, current);
|
|
924
|
+
throw e;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
### 5.2 Protection processus orphelins
|
|
930
|
+
|
|
931
|
+
| Strategie | Detail |
|
|
932
|
+
|-----------|--------|
|
|
933
|
+
| **PID file** | Ecrire le PID dans `jar_files/.bridge-{port}.pid` au demarrage |
|
|
934
|
+
| **process.on('exit')** | Enregistrer un handler qui arrete tous les bridges a la sortie de Node |
|
|
935
|
+
| **process.on('SIGINT/SIGTERM')** | Idem pour Ctrl+C et kill |
|
|
936
|
+
| **uncaughtException** | Arreter les bridges meme en cas de crash |
|
|
937
|
+
| **Health check periodique** | Verifier toutes les 30s que les bridges sont vivants |
|
|
938
|
+
| **Cleanup au demarrage** | Verifier les PID files au demarrage, tuer les orphelins |
|
|
939
|
+
|
|
940
|
+
```typescript
|
|
941
|
+
// Dans BridgeManager constructor :
|
|
942
|
+
|
|
943
|
+
constructor() {
|
|
944
|
+
// Cleanup global — arreter tous les bridges quand Node s'arrete
|
|
945
|
+
const cleanup = () => this.stopAllSync();
|
|
946
|
+
|
|
947
|
+
process.on('exit', cleanup);
|
|
948
|
+
process.on('SIGINT', () => { cleanup(); process.exit(0); });
|
|
949
|
+
process.on('SIGTERM', () => { cleanup(); process.exit(0); });
|
|
950
|
+
process.on('uncaughtException', (err) => {
|
|
951
|
+
console.error('[BridgeManager] Uncaught exception — stopping bridges', err);
|
|
952
|
+
cleanup();
|
|
953
|
+
process.exit(1);
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
// Nettoyer les orphelins du demarrage precedent
|
|
957
|
+
this.cleanupOrphans();
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
private cleanupOrphans(): void {
|
|
961
|
+
// Lire les fichiers .bridge-*.pid dans jar_files/
|
|
962
|
+
// Pour chaque PID : verifier si le process existe encore
|
|
963
|
+
// Si oui : le tuer (c'est un orphelin d'un run precedent)
|
|
964
|
+
// Supprimer le fichier PID
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
private stopAllSync(): void {
|
|
968
|
+
for (const [key, bridge] of this.bridges) {
|
|
969
|
+
try { bridge.process.kill('SIGTERM'); } catch {}
|
|
970
|
+
this.removePidFile(bridge.port);
|
|
971
|
+
}
|
|
972
|
+
this.bridges.clear();
|
|
973
|
+
}
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
### 5.3 PID File format
|
|
977
|
+
|
|
978
|
+
```
|
|
979
|
+
jar_files/.bridge-8765.pid
|
|
980
|
+
contenu : 12345
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
Au demarrage :
|
|
984
|
+
1. Lire `.bridge-8765.pid` → PID 12345
|
|
985
|
+
2. Verifier `kill(12345, 0)` → process existe ?
|
|
986
|
+
3. Si oui → tuer `kill(12345, 'SIGTERM')`
|
|
987
|
+
4. Supprimer le fichier `.bridge-8765.pid`
|
|
988
|
+
5. Le port 8765 est maintenant libre
|
|
989
|
+
|
|
990
|
+
---
|
|
991
|
+
|
|
992
|
+
## 6. Variables .env
|
|
993
|
+
|
|
994
|
+
### 6.1 Liste complete
|
|
995
|
+
|
|
996
|
+
```bash
|
|
997
|
+
# ============================================================
|
|
998
|
+
# JDBC Bridge — Configuration (.env.local)
|
|
999
|
+
# ============================================================
|
|
1000
|
+
|
|
1001
|
+
# Demarrage automatique du bridge JDBC (defaut: true)
|
|
1002
|
+
# true = lance le bridge si JAR present
|
|
1003
|
+
# false = ne lance jamais (demarrage manuel requis)
|
|
1004
|
+
# detect = reutilise un bridge existant ou en lance un nouveau
|
|
1005
|
+
MOSTA_BRIDGE_AUTOSTART=true
|
|
1006
|
+
|
|
1007
|
+
# Port de base pour le premier bridge (defaut: 8765)
|
|
1008
|
+
MOSTA_BRIDGE_PORT_BASE=8765
|
|
1009
|
+
|
|
1010
|
+
# Incrementation automatique des ports (defaut: true)
|
|
1011
|
+
# true = chaque bridge prend le port suivant (8765, 8766, 8767...)
|
|
1012
|
+
# false = tous sur le meme port (erreur si conflit)
|
|
1013
|
+
MOSTA_BRIDGE_PORT_INCREMENT=true
|
|
1014
|
+
|
|
1015
|
+
# Repertoire des fichiers JAR JDBC (defaut: auto-detect jar_files/)
|
|
1016
|
+
MOSTA_JAR_DIR=/home/hmd/dev/MostaGare-Install/mostajs/jar_files
|
|
1017
|
+
|
|
1018
|
+
# Chemin vers MostaJdbcBridge.java (defaut: auto-detect bridge/)
|
|
1019
|
+
MOSTA_BRIDGE_JAVA=/home/hmd/dev/MostaGare-Install/mostajs/mosta-orm/bridge/MostaJdbcBridge.java
|
|
1020
|
+
|
|
1021
|
+
# Nombre max de tentatives de demarrage avant abandon (defaut: 3)
|
|
1022
|
+
MOSTA_BRIDGE_MAX_RETRIES=3
|
|
1023
|
+
|
|
1024
|
+
# Timeout en ms pour attendre que le bridge soit pret (defaut: 15000)
|
|
1025
|
+
MOSTA_BRIDGE_TIMEOUT=15000
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
### 6.2 Exemple de configurations
|
|
1029
|
+
|
|
1030
|
+
#### Developpement local (multi-base)
|
|
1031
|
+
|
|
1032
|
+
```bash
|
|
1033
|
+
MOSTA_BRIDGE_AUTOSTART=true
|
|
1034
|
+
MOSTA_BRIDGE_PORT_INCREMENT=true
|
|
1035
|
+
MOSTA_BRIDGE_PORT_BASE=8765
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
→ HSQLDB sur 8765, Oracle sur 8766 si besoin
|
|
1039
|
+
|
|
1040
|
+
#### Production (bridge demarrage manuel)
|
|
1041
|
+
|
|
1042
|
+
```bash
|
|
1043
|
+
MOSTA_BRIDGE_AUTOSTART=false
|
|
1044
|
+
```
|
|
1045
|
+
|
|
1046
|
+
→ L'admin lance le bridge avec systemd/docker
|
|
1047
|
+
→ L'app se connecte au bridge deja en cours
|
|
1048
|
+
|
|
1049
|
+
#### CI/CD (detection)
|
|
1050
|
+
|
|
1051
|
+
```bash
|
|
1052
|
+
MOSTA_BRIDGE_AUTOSTART=detect
|
|
1053
|
+
MOSTA_BRIDGE_PORT_BASE=9900
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
→ Reutilise le bridge d'un test precedent si encore actif
|
|
1057
|
+
→ Ports hauts pour eviter les conflits
|
|
1058
|
+
|
|
1059
|
+
---
|
|
1060
|
+
|
|
1061
|
+
## 7. Plan d'implementation
|
|
1062
|
+
|
|
1063
|
+
### Phase 1 : Renommage (faible risque)
|
|
1064
|
+
|
|
1065
|
+
| Etape | Fichier | Action | Complexite |
|
|
1066
|
+
|-------|---------|--------|------------|
|
|
1067
|
+
| 1.1 | `abstract-sql.dialect.ts` | Renommer classe → `SessionMostaORMFactory` | Simple |
|
|
1068
|
+
| 1.2 | `abstract-sql.dialect.ts` | Ajouter alias `AbstractSqlDialect` pour retrocompatibilite | Simple |
|
|
1069
|
+
| 1.3 | `abstract-sql.dialect.ts` | Renommer fichier → `session-factory.ts` | Simple |
|
|
1070
|
+
| 1.4 | 8 dialects | Mettre a jour `import` et `extends` | Repetitif |
|
|
1071
|
+
| 1.5 | `index.ts` | Ajouter export `SessionMostaORMFactory` | Simple |
|
|
1072
|
+
| 1.6 | Commentaires | Mettre a jour les references dans JdbcNormalizer, docs | Simple |
|
|
1073
|
+
| 1.7 | Build + test | `tsc` + verification | Validation |
|
|
1074
|
+
|
|
1075
|
+
### Phase 2 : BridgeManager multi-instance (risque moyen)
|
|
1076
|
+
|
|
1077
|
+
| Etape | Fichier | Action | Complexite |
|
|
1078
|
+
|-------|---------|--------|------------|
|
|
1079
|
+
| 2.1 | `src/bridge/BridgeManager.ts` | Creer la classe singleton BridgeManager | Moyen |
|
|
1080
|
+
| 2.2 | `src/bridge/BridgeManager.ts` | Gestion des ports (base + increment) | Simple |
|
|
1081
|
+
| 2.3 | `src/bridge/BridgeManager.ts` | Map des bridges actifs par cle | Simple |
|
|
1082
|
+
| 2.4 | `src/bridge/BridgeManager.ts` | Reutilisation si meme cle | Simple |
|
|
1083
|
+
| 2.5 | `session-factory.ts` | Remplacer JdbcNormalizer direct par BridgeManager | Moyen |
|
|
1084
|
+
| 2.6 | `session-factory.ts` | `disconnect()` ne tue plus le bridge (BridgeManager gere) | Simple |
|
|
1085
|
+
| 2.7 | `JdbcNormalizer.ts` | Deviens interne au BridgeManager (ou supprime) | Moyen |
|
|
1086
|
+
| 2.8 | `index.ts` | Exporter BridgeManager | Simple |
|
|
1087
|
+
| 2.9 | Build + test | Test avec 2 bridges simultanees | Validation |
|
|
1088
|
+
|
|
1089
|
+
### Phase 3 : Auto-Start controlable (risque moyen)
|
|
1090
|
+
|
|
1091
|
+
| Etape | Fichier | Action | Complexite |
|
|
1092
|
+
|-------|---------|--------|------------|
|
|
1093
|
+
| 3.1 | `src/bridge/BridgeManager.ts` | Lire MOSTA_BRIDGE_AUTOSTART depuis process.env | Simple |
|
|
1094
|
+
| 3.2 | `session-factory.ts` | Implementer la logique true/false/detect | Moyen |
|
|
1095
|
+
| 3.3 | `src/bridge/BridgeManager.ts` | Mode detect : health check avant lancement | Simple |
|
|
1096
|
+
| 3.4 | `session-factory.ts` | Si autostart=false ET pas de driver npm → erreur claire | Simple |
|
|
1097
|
+
| 3.5 | Build + test | Test des 3 modes | Validation |
|
|
1098
|
+
|
|
1099
|
+
### Phase 4 : Protections (risque faible)
|
|
1100
|
+
|
|
1101
|
+
| Etape | Fichier | Action | Complexite |
|
|
1102
|
+
|-------|---------|--------|------------|
|
|
1103
|
+
| 4.1 | `src/bridge/BridgeManager.ts` | Anti-boucle : compteur de tentatives + timeout | Moyen |
|
|
1104
|
+
| 4.2 | `src/bridge/BridgeManager.ts` | PID files : ecriture au start, lecture au cleanup | Simple |
|
|
1105
|
+
| 4.3 | `src/bridge/BridgeManager.ts` | Cleanup orphelins au demarrage du BridgeManager | Moyen |
|
|
1106
|
+
| 4.4 | `src/bridge/BridgeManager.ts` | process.on('exit/SIGINT/SIGTERM') → stopAll | Simple |
|
|
1107
|
+
| 4.5 | `src/bridge/BridgeManager.ts` | Detection port occupe avant lancement | Simple |
|
|
1108
|
+
| 4.6 | Build + test | Test crash + restart + orphelins | Validation |
|
|
1109
|
+
|
|
1110
|
+
### Phase 5 : Documentation et cleanup
|
|
1111
|
+
|
|
1112
|
+
| Etape | Action | Complexite |
|
|
1113
|
+
|-------|--------|------------|
|
|
1114
|
+
| 5.1 | Mettre a jour jdbc-normalizer-study.md | Simple |
|
|
1115
|
+
| 5.2 | Mettre a jour audit-dialects-vs-hibernate.md | Simple |
|
|
1116
|
+
| 5.3 | Supprimer le backup `_hsqldb.dialect (copie).ts_` | Simple |
|
|
1117
|
+
| 5.4 | Build final `tsc` + verification dist/ | Validation |
|
|
1118
|
+
|
|
1119
|
+
---
|
|
1120
|
+
|
|
1121
|
+
## 8. Matrice de risques
|
|
1122
|
+
|
|
1123
|
+
| Risque | Probabilite | Impact | Mitigation |
|
|
1124
|
+
|--------|-------------|--------|------------|
|
|
1125
|
+
| Regression sur les dialects npm (pg, mysql2...) | Faible | Haut | Le renommage ne touche pas la logique, juste les noms |
|
|
1126
|
+
| Port deja occupe | Moyen | Moyen | Detection avant lancement + increment |
|
|
1127
|
+
| Process Java orphelin | Moyen | Faible | PID files + cleanup au demarrage + process.on('exit') |
|
|
1128
|
+
| Boucle de relance | Faible | Haut | Compteur max 3 tentatives + timeout |
|
|
1129
|
+
| Java non installe | Moyen | Moyen | Message d'erreur clair + mode autostart=false |
|
|
1130
|
+
| 2 bridges meme JDBC URL | Faible | Moyen | Cle unique par bridge, reutilisation |
|
|
1131
|
+
| Crash Node sans cleanup | Moyen | Moyen | PID files persistent + cleanup orphelins au restart |
|
|
1132
|
+
| Trop de bridges ouverts | Faible | Moyen | Limite configurable (max 10 bridges) |
|
|
1133
|
+
|
|
1134
|
+
---
|
|
1135
|
+
|
|
1136
|
+
## Annexe : Structure finale des fichiers
|
|
1137
|
+
|
|
1138
|
+
```
|
|
1139
|
+
mosta-orm/
|
|
1140
|
+
├── src/
|
|
1141
|
+
│ ├── index.ts
|
|
1142
|
+
│ ├── core/
|
|
1143
|
+
│ │ ├── types.ts
|
|
1144
|
+
│ │ ├── factory.ts
|
|
1145
|
+
│ │ ├── config.ts
|
|
1146
|
+
│ │ ├── registry.ts
|
|
1147
|
+
│ │ ├── base-repository.ts
|
|
1148
|
+
│ │ ├── normalizer.ts
|
|
1149
|
+
│ │ └── errors.ts
|
|
1150
|
+
│ ├── dialects/
|
|
1151
|
+
│ │ ├── session-factory.ts ← ex abstract-sql.dialect.ts (renomme)
|
|
1152
|
+
│ │ ├── mongo.dialect.ts
|
|
1153
|
+
│ │ ├── sqlite.dialect.ts
|
|
1154
|
+
│ │ ├── postgres.dialect.ts
|
|
1155
|
+
│ │ ├── mysql.dialect.ts
|
|
1156
|
+
│ │ ├── mariadb.dialect.ts
|
|
1157
|
+
│ │ ├── oracle.dialect.ts
|
|
1158
|
+
│ │ ├── mssql.dialect.ts
|
|
1159
|
+
│ │ ├── cockroachdb.dialect.ts
|
|
1160
|
+
│ │ ├── db2.dialect.ts
|
|
1161
|
+
│ │ ├── hana.dialect.ts
|
|
1162
|
+
│ │ ├── hsqldb.dialect.ts
|
|
1163
|
+
│ │ ├── spanner.dialect.ts
|
|
1164
|
+
│ │ └── sybase.dialect.ts
|
|
1165
|
+
│ └── bridge/
|
|
1166
|
+
│ ├── jdbc-registry.ts ← table dialect → JAR → JDBC URL
|
|
1167
|
+
│ ├── JdbcNormalizer.ts ← lancement d'UN bridge (bas niveau)
|
|
1168
|
+
│ └── BridgeManager.ts ← NOUVEAU : singleton multi-bridge
|
|
1169
|
+
├── bridge/
|
|
1170
|
+
│ └── MostaJdbcBridge.java ← bridge HTTP-JDBC universel
|
|
1171
|
+
├── jar_files/ ← JARs JDBC (gitignore)
|
|
1172
|
+
│ ├── hsqldb-2.7.2.jar
|
|
1173
|
+
│ ├── .bridge-8765.pid ← PID file (auto-genere)
|
|
1174
|
+
│ └── .bridge-8766.pid
|
|
1175
|
+
└── docs/
|
|
1176
|
+
├── jdbc-normalizer-study.md
|
|
1177
|
+
├── audit-dialects-vs-hibernate.md
|
|
1178
|
+
└── plan-session-factory-multi-bridge.md ← ce document
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1181
|
+
### Vos points :
|
|
1182
|
+
|
|
1183
|
+
1. Le fichier .env ne peut pas être en dur
|
|
1184
|
+
|
|
1185
|
+
Vous avez raison. Le BridgeManager lit déjà process.env dynamiquement — il
|
|
1186
|
+
ne hardcode pas de fichier .env. Peu importe si c'est .env, .env.local, ou
|
|
1187
|
+
.env.production, c'est Next.js (ou dotenv) qui charge les variables dans
|
|
1188
|
+
process.env, et le BridgeManager les lit de là. Rien à changer côté ORM.
|
|
1189
|
+
|
|
1190
|
+
2. Ne changer le port que si on change de SGBD — si même SGBD déjà lancé,
|
|
1191
|
+
ne pas relancer
|
|
1192
|
+
|
|
1193
|
+
C'est exactement le comportement implémenté. Le BridgeManager.getOrCreate()
|
|
1194
|
+
utilise une clé unique par SGBD :
|
|
1195
|
+
|
|
1196
|
+
clé = `${dialect}:${host}:${port}/${database}`
|
|
1197
|
+
|
|
1198
|
+
- Même SGBD, même URI → la clé est identique → le bridge existant est
|
|
1199
|
+
réutilisé (pas de nouveau process, même port)
|
|
1200
|
+
- SGBD différent (ou URI différente) → nouvelle clé → nouveau bridge sur le
|
|
1201
|
+
port suivant
|
|
1202
|
+
|
|
1203
|
+
Laissez-moi ajuster le BridgeManager pour renforcer cette logique — le port
|
|
1204
|
+
ne doit s'incrémenter qu'au lancement d'un nouveau bridge, pas à chaque
|
|
1205
|
+
appel.
|
|
1206
|
+
|
|
1207
|
+
● Read 1 file (ctrl+o to expand)
|
|
1208
|
+
|
|
1209
|
+
● La logique est déjà correcte. Récapitulons le flux :
|
|
1210
|
+
|
|
1211
|
+
1. getOrCreate("hsqldb", "hsqldb:hsql://localhost:9001/") → clé =
|
|
1212
|
+
hsqldb:localhost:9001/ → nouveau bridge port 8765
|
|
1213
|
+
2. getOrCreate("hsqldb", "hsqldb:hsql://localhost:9001/") → même clé →
|
|
1214
|
+
réutilise bridge port 8765 (pas de relancement)
|
|
1215
|
+
3. getOrCreate("oracle", "oracle://host:1521/db") → clé différente →
|
|
1216
|
+
nouveau bridge port 8766
|
|
1217
|
+
4. getOrCreate("oracle", "oracle://host:1521/db") → même clé → réutilise
|
|
1218
|
+
bridge port 8766
|
|
1219
|
+
|
|
1220
|
+
Le port ne s'incrémente que quand un nouveau SGBD distinct est connecté. Si
|
|
1221
|
+
le même SGBD est déjà lancé, il est réutilisé directement sans toucher aux
|
|
1222
|
+
ports.
|
|
1223
|
+
|
|
1224
|
+
La compilation TypeScript passe sans erreurs. Les phases 2-4 du plan sont
|
|
1225
|
+
implémentées dans BridgeManager.ts :
|
|
1226
|
+
- Multi-bridge avec clé unique par SGBD
|
|
1227
|
+
- Autostart contrôlable via process.env.MOSTA_BRIDGE_AUTOSTART
|
|
1228
|
+
(true/false/detect)
|
|
1229
|
+
- Protection anti-boucle (max 3 tentatives en 60s)
|
|
1230
|
+
- PID files + cleanup orphelins au démarrage
|
|
1231
|
+
- process.on('exit/SIGINT/SIGTERM') → stopAll()
|
|
1232
|
+
- Détection port occupé avec incrémentation automatique
|
|
1233
|
+
|