Skip to content

Commit 6a9b7ef

Browse files
committed
library-api: optimize hot reload code generation
it was rebuilding the model registry on every API request. Now it only builds the registry if a DMN model was changed.
1 parent a00b54d commit 6a9b7ef

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

library-api/src/main/java/org/codeforphilly/bdt/api/ModelRegistry.java

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,39 +45,59 @@ public class ModelRegistry {
4545
@Inject
4646
org.kie.kogito.Application application;
4747

48+
/**
49+
* Cached model registry built once at startup.
50+
* Volatile to ensure visibility across threads.
51+
*/
52+
private volatile Map<String, ModelInfo> cachedModels;
53+
54+
/**
55+
* Cached path-to-model mapping built once at startup.
56+
* Volatile to ensure visibility across threads.
57+
*/
58+
private volatile Map<String, ModelInfo> cachedModelsByPath;
59+
4860
/**
4961
* Get metadata for a specific model by name.
62+
* Returns cached result built at startup.
5063
*
5164
* @param modelName the DMN model name (e.g., "PersonMinAge", "PhlHomesteadExemption")
5265
* @return ModelInfo containing namespace and available services, or null if not found
5366
*/
5467
public ModelInfo getModelInfo(String modelName) {
55-
Map<String, ModelInfo> allModels = getAllModels();
56-
return allModels.get(modelName);
68+
return cachedModels.get(modelName);
5769
}
5870

5971
/**
6072
* Get metadata for a specific model by path.
73+
* Returns cached result built at startup.
6174
*
6275
* @param path the relative path (e.g., "age/PersonMinAge", "checks/test/TestOne")
6376
* @return ModelInfo or null if not found
6477
*/
6578
public ModelInfo getModelInfoByPath(String path) {
66-
Map<String, ModelInfo> allModels = getAllModels();
67-
return allModels.values().stream()
68-
.filter(info -> info.getPath().equals(path))
69-
.findFirst()
70-
.orElse(null);
79+
return cachedModelsByPath.get(path);
7180
}
7281

7382
/**
7483
* Get all discovered DMN models.
75-
* Rebuilds the mapping on each call to ensure hot-reload compatibility.
84+
* Returns cached results built once at startup.
85+
* Hot-reload compatibility: Quarkus dev mode reloads the entire class, triggering cache rebuild.
7686
*
7787
* @return map of model name to ModelInfo
7888
*/
7989
public Map<String, ModelInfo> getAllModels() {
90+
return cachedModels;
91+
}
92+
93+
/**
94+
* Build the model registry cache.
95+
* This is called once during @PostConstruct initialization.
96+
* Scans the classpath for DMN files and builds the model metadata registry.
97+
*/
98+
private void buildModelCache() {
8099
Map<String, ModelInfo> modelMap = new HashMap<>();
100+
Map<String, ModelInfo> modelsByPath = new HashMap<>();
81101

82102
try {
83103
// Build mappings of model name -> file path and model name -> description
@@ -89,7 +109,9 @@ public Map<String, ModelInfo> getAllModels() {
89109

90110
if (dmnRuntime == null) {
91111
log.warn("DMNRuntime is null, no models discovered");
92-
return modelMap;
112+
this.cachedModels = modelMap;
113+
this.cachedModelsByPath = modelsByPath;
114+
return;
93115
}
94116

95117
List<DMNModel> models = dmnRuntime.getModels();
@@ -113,27 +135,37 @@ public Map<String, ModelInfo> getAllModels() {
113135

114136
ModelInfo info = new ModelInfo(namespace, modelName, decisionServices, decisions, path, description);
115137
modelMap.put(modelName, info);
138+
modelsByPath.put(path, info);
116139

117140
log.debug("Registered model: {} (namespace: {}, services: {}, decisions: {}, path: {}, description: {})",
118141
modelName, namespace, decisionServices.size(), decisions.size(), path,
119142
description != null ? description.substring(0, Math.min(30, description.length())) + "..." : "null");
120143
}
121144

145+
log.info("Model registry cache built: {} models registered", modelMap.size());
146+
122147
} catch (Exception e) {
123-
log.error("Error discovering DMN models", e);
148+
log.error("Error building DMN model cache", e);
124149
}
125150

126-
return modelMap;
151+
// Assign to volatile fields for thread-safe publication
152+
this.cachedModels = modelMap;
153+
this.cachedModelsByPath = modelsByPath;
127154
}
128155

129156
/**
130-
* Validates that all DMN model names are unique.
131-
* This runs at application startup and on every hot reload to ensure no duplicate model names exist.
157+
* Initializes the model registry and validates that all DMN model names are unique.
158+
* This runs at application startup and on every hot reload.
159+
* Builds the model cache FIRST, then validates for duplicate model names.
132160
*
133161
* @throws IllegalStateException if duplicate model names are detected
134162
*/
135163
@PostConstruct
136-
public void validateUniqueModelNames() {
164+
public void initialize() {
165+
// Build the cache first
166+
buildModelCache();
167+
168+
// Then validate model names
137169
try {
138170
// Get models directly from DMNRuntime BEFORE deduplication
139171
DecisionModels decisionModels = application.get(DecisionModels.class);

0 commit comments

Comments
 (0)