@@ -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