1919import java .util .Map .Entry ;
2020import java .util .Objects ;
2121
22- import org .eclipse .microprofile .config .ConfigProvider ;
2322import org .osgi .service .component .annotations .Component ;
2423import org .osgi .service .component .annotations .ConfigurationPolicy ;
2524import org .osgi .service .component .annotations .Reference ;
3635import com .ibm .ws .kernel .feature .ServerStartedPhase2 ;
3736import com .ibm .wsspi .kernel .service .utils .FrameworkState ;
3837
38+ import io .openliberty .microprofile .openapi .internal .common .services .OpenAPIAppConfigProvider ;
3939import io .openliberty .microprofile .openapi20 .internal .services .ApplicationRegistry ;
4040import io .openliberty .microprofile .openapi20 .internal .services .MergeProcessor ;
41+ import io .openliberty .microprofile .openapi20 .internal .services .ModuleSelectionConfig ;
4142import io .openliberty .microprofile .openapi20 .internal .services .OpenAPIProvider ;
42- import io .openliberty .microprofile .openapi20 .internal .utils .Constants ;
4343import io .openliberty .microprofile .openapi20 .internal .utils .LoggingUtils ;
4444import io .openliberty .microprofile .openapi20 .internal .utils .MessageConstants ;
4545import io .openliberty .microprofile .openapi20 .internal .utils .ModuleUtils ;
5252 * OpenAPI documentation is generated for each web module and then merged together if merging is enabled. If merging is not enabled,
5353 * then documentation is only generated for the first web module found.
5454 */
55- @ Component (configurationPolicy = ConfigurationPolicy .IGNORE , service = ApplicationRegistry . class )
56- public class ApplicationRegistryImpl implements ApplicationRegistry {
55+ @ Component (configurationPolicy = ConfigurationPolicy .IGNORE )
56+ public class ApplicationRegistryImpl implements ApplicationRegistry , OpenAPIAppConfigProvider . OpenAPIAppConfigListener {
5757
5858 private static final TraceComponent tc = Tr .register (ApplicationRegistryImpl .class );
5959
@@ -66,13 +66,22 @@ public class ApplicationRegistryImpl implements ApplicationRegistry {
6666 @ Reference
6767 private MergeProcessor mergeProcessor ;
6868
69+ @ Reference (cardinality = ReferenceCardinality .MANDATORY , policy = ReferencePolicy .STATIC , unbind = "unbindAppConfigListener" )
70+ public void bindAppConfigListener (OpenAPIAppConfigProvider openAPIAppConfigProvider ) {
71+ openAPIAppConfigProvider .registerAppConfigListener (this );
72+ }
73+
74+ public void unbindAppConfigListener (OpenAPIAppConfigProvider openAPIAppConfigProvider ) {
75+ openAPIAppConfigProvider .unregisterAppConfigListener (this );
76+ }
77+
6978 // Thread safety: access to these fields must be synchronized on this
70- private final Map <String , ApplicationRecord > applications = new LinkedHashMap <>(); // Linked map retains order in which applications were added
79+ private Map <String , ApplicationRecord > applications = new LinkedHashMap <>(); // Linked map retains order in which applications were added
7180
7281 private OpenAPIProvider cachedProvider = null ;
7382
74- // Lazily initialized, use getModuleSelectionConfig() instead
75- private ModuleSelectionConfig moduleSelectionConfig = null ;
83+ @ Reference
84+ private ModuleSelectionConfig moduleSelectionConfig ;
7685
7786 /**
7887 * The addApplication method is invoked by the {@link ApplicationListener} when it is notified that an application
@@ -95,13 +104,13 @@ public void addApplication(ApplicationInfo newAppInfo) {
95104
96105 OpenAPIProvider firstProvider = getFirstProvider ();
97106
98- if (getModuleSelectionConfig () .useFirstModuleOnly () && firstProvider != null ) {
107+ if (moduleSelectionConfig .useFirstModuleOnly () && firstProvider != null ) {
99108 if (LoggingUtils .isEventEnabled (tc )) {
100109 Tr .event (this , tc , "Application Processor: useFirstModuleOnly is configured and we already have a module. Not processing. appInfo=" + newAppInfo );
101110 }
102111 mergeDisabledAlerter .setUsingMultiModulesWithoutConfig (firstProvider );
103112 } else {
104- Collection <OpenAPIProvider > openApiProviders = applicationProcessor .processApplication (newAppInfo , getModuleSelectionConfig () );
113+ Collection <OpenAPIProvider > openApiProviders = applicationProcessor .processApplication (newAppInfo , moduleSelectionConfig );
105114
106115 if (!openApiProviders .isEmpty ()) {
107116 // If the new application has any providers, invalidate the model cache
@@ -139,15 +148,15 @@ public void removeApplication(ApplicationInfo removedAppInfo) {
139148 // If the removed application had any providers, invalidate the provider cache
140149 cachedProvider = null ;
141150
142- if (getModuleSelectionConfig () .useFirstModuleOnly () && !FrameworkState .isStopping ()) {
151+ if (moduleSelectionConfig .useFirstModuleOnly () && !FrameworkState .isStopping ()) {
143152 if (LoggingUtils .isEventEnabled (tc )) {
144153 Tr .event (this , tc , "Application Processor: Current OpenAPI application removed, looking for another application to document." );
145154 }
146155
147156 // We just removed the module used for the OpenAPI document and the server is not shutting down.
148157 // We need to find a new module to use if there is one
149158 for (ApplicationRecord app : applications .values ()) {
150- Collection <OpenAPIProvider > providers = applicationProcessor .processApplication (app .info , getModuleSelectionConfig () );
159+ Collection <OpenAPIProvider > providers = applicationProcessor .processApplication (app .info , moduleSelectionConfig );
151160 if (!providers .isEmpty ()) {
152161 app .providers .addAll (providers );
153162 break ;
@@ -192,9 +201,7 @@ protected void setServerStartPhase2(ServerStartedPhase2 event) {
192201 // Couldn't read this application for some reason, but that means we can't have been able to include modules from it anyway.
193202 }
194203 }
195- for (String unmatchedInclude : getModuleSelectionConfig ().findIncludesNotMatchingAnything (modules )) {
196- Tr .warning (tc , MessageConstants .OPENAPI_MERGE_UNUSED_INCLUDE_CWWKO1667W , Constants .MERGE_INCLUDE_CONFIG , unmatchedInclude );
197- }
204+ moduleSelectionConfig .sendWarningsForAppsAndModulesNotMatchingAnything (modules );
198205 }
199206 }
200207
@@ -242,6 +249,9 @@ public OpenAPIProvider getOpenAPIProvider() {
242249 }
243250
244251 cachedProvider = result ;
252+ if (LoggingUtils .isEventEnabled (tc )) {
253+ Tr .event (this , tc , "Finished creating OpenAPI provider" );
254+ }
245255 return result ;
246256 }
247257 }
@@ -254,19 +264,6 @@ private List<OpenAPIProvider> getProvidersToMerge() {
254264 }
255265 }
256266
257- /**
258- * Thread safety: Caller must hold lock on {@code this}
259- *
260- * @return the module selection config
261- */
262- private ModuleSelectionConfig getModuleSelectionConfig () {
263- if (moduleSelectionConfig == null ) {
264- // Lazy initialization to avoid calling getConfig() before Config is ready
265- moduleSelectionConfig = ModuleSelectionConfig .fromConfig (ConfigProvider .getConfig (ApplicationRegistryImpl .class .getClassLoader ()));
266- }
267- return moduleSelectionConfig ;
268- }
269-
270267 /**
271268 * Thread safety: Caller must hold lock on {@code this}
272269 *
@@ -282,6 +279,20 @@ private OpenAPIProvider getFirstProvider() {
282279 return null ;
283280 }
284281
282+ @ Override
283+ public void processConfigUpdate () {
284+ synchronized (this ) {
285+ Map <String , ApplicationRecord > oldApps = applications ;
286+ applications = new LinkedHashMap <>();
287+ for (ApplicationRecord record : oldApps .values ()) {
288+ //Add application uses config to decide if it creates and registers any providers in ApplicationInfo
289+ //Rather than map from the old state to the new state when the config changes, KISS and start again.
290+ addApplication (record .info );
291+ }
292+ cachedProvider = null ;
293+ }
294+ }
295+
285296 private static class ApplicationRecord {
286297 public ApplicationRecord (ApplicationInfo info ) {
287298 this .info = info ;
@@ -291,4 +302,10 @@ public ApplicationRecord(ApplicationInfo info) {
291302 private final List <OpenAPIProvider > providers = new ArrayList <>();
292303 }
293304
305+ //This is to ensure we're called after ModuleSelectionConfigImpl
306+ @ Override
307+ public int getConfigListenerPriority () {
308+ return 2 ;
309+ }
310+
294311}
0 commit comments