Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

28857 openapi include exclude #29769

Draft
wants to merge 3 commits into
base: integration
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added dev/com.ibm.ws.cdi.api_fat/autoFVT.zip
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ public void refreshServerXMLFromPublish() throws Exception {
/**
* Swaps in a different server.xml file from the server directory.
*
* @param fileName
* @param fileName the name of a server.xml file found in the wlp/usr/[server]/ directory
* @throws Exception
*/
public void swapInServerXMLFromPublish(String fileName) throws Exception {
Expand Down
5 changes: 3 additions & 2 deletions dev/io.openliberty.microprofile.openapi.2.0.internal/bnd.bnd
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#*******************************************************************************
# Copyright (c) 2020, 2024 IBM Corporation and others.
# Copyright (c) 2020, 2022 IBM Corporation and others.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect copyright date change?

# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
# which accompanies this distribution, and is available at
Expand Down Expand Up @@ -55,7 +55,8 @@ IBM-Default-Config: OSGI-INF/wlp/defaultInstances.xml
io.openliberty.microprofile.openapi20.internal.css.CustomCSSProcessor,\
io.openliberty.microprofile.openapi20.internal.DefaultHostListenerImpl,\
io.openliberty.microprofile.openapi20.internal.cache.ConfigSerializer,\
io.openliberty.microprofile.openapi20.internal.validation.OASValidator30Impl
io.openliberty.microprofile.openapi20.internal.validation.OASValidator30Impl,\
io.openliberty.microprofile.openapi20.internal.ModuleSelectionConfigImpl

WS-TraceGroup: MPOPENAPI

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import io.openliberty.microprofile.openapi20.internal.cache.ConfigSerializer;
import io.openliberty.microprofile.openapi20.internal.services.ConfigFieldProvider;
import io.openliberty.microprofile.openapi20.internal.services.ModelGenerator;
import io.openliberty.microprofile.openapi20.internal.services.ModuleSelectionConfig;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spurious import

import io.openliberty.microprofile.openapi20.internal.services.OpenAPIProvider;
import io.openliberty.microprofile.openapi20.internal.utils.Constants;
import io.openliberty.microprofile.openapi20.internal.utils.IndexUtils;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.util.Map.Entry;
import java.util.Objects;

import org.eclipse.microprofile.config.ConfigProvider;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
Expand All @@ -36,10 +35,12 @@
import com.ibm.ws.kernel.feature.ServerStartedPhase2;
import com.ibm.wsspi.kernel.service.utils.FrameworkState;

import io.openliberty.microprofile.openapi.internal.common.services.OpenAPIAppConfigProvider;
import io.openliberty.microprofile.openapi.internal.common.services.OpenAPIAppConfigProvider.OpenAPIAppConfigListener;
import io.openliberty.microprofile.openapi20.internal.services.ApplicationRegistry;
import io.openliberty.microprofile.openapi20.internal.services.MergeProcessor;
import io.openliberty.microprofile.openapi20.internal.services.ModuleSelectionConfig;
import io.openliberty.microprofile.openapi20.internal.services.OpenAPIProvider;
import io.openliberty.microprofile.openapi20.internal.utils.Constants;
import io.openliberty.microprofile.openapi20.internal.utils.LoggingUtils;
import io.openliberty.microprofile.openapi20.internal.utils.MessageConstants;
import io.openliberty.microprofile.openapi20.internal.utils.ModuleUtils;
Expand All @@ -52,8 +53,8 @@
* OpenAPI documentation is generated for each web module and then merged together if merging is enabled. If merging is not enabled,
* then documentation is only generated for the first web module found.
*/
@Component(configurationPolicy = ConfigurationPolicy.IGNORE, service = ApplicationRegistry.class)
public class ApplicationRegistryImpl implements ApplicationRegistry {
@Component(configurationPolicy = ConfigurationPolicy.IGNORE)
public class ApplicationRegistryImpl implements ApplicationRegistry, OpenAPIAppConfigProvider.OpenAPIAppConfigListener {

private static final TraceComponent tc = Tr.register(ApplicationRegistryImpl.class);

Expand All @@ -66,13 +67,33 @@ public class ApplicationRegistryImpl implements ApplicationRegistry {
@Reference
private MergeProcessor mergeProcessor;

@SuppressWarnings("unused")
private OpenAPIAppConfigProvider openAPIAppConfigProvider;
Comment on lines +70 to +71
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove SuppressWarnings


@Reference(cardinality = ReferenceCardinality.MANDATORY, policy = ReferencePolicy.STATIC, unbind = "unbindAppConfigListener")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unbind is not necessary here, it gets inferred based on the method names.

public void bindAppConfigListener(OpenAPIAppConfigProvider openAPIAppConfigProvider) {
this.openAPIAppConfigProvider = openAPIAppConfigProvider;
openAPIAppConfigProvider.registerAppConfigListener(this);
}

public void unbindAppConfigListener(OpenAPIAppConfigProvider openAPIAppConfigProvider) {
openAPIAppConfigProvider.unregisterAppConfigListener(this);
this.openAPIAppConfigProvider = null;
}

@Reference
public void bindOpenAPIAppConfigProvider(OpenAPIAppConfigProvider openAPIAppConfigProvider) {
this.openAPIAppConfigProvider = null;
openAPIAppConfigProvider.registerAppConfigListener(this);
}
Comment on lines +74 to +88
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like you have two references to OpenAPIAppConfigProvider, but the first one is named appConfigListener.


// Thread safety: access to these fields must be synchronized on this
private final Map<String, ApplicationRecord> applications = new LinkedHashMap<>(); // Linked map retains order in which applications were added
private Map<String, ApplicationRecord> applications = new LinkedHashMap<>(); // Linked map retains order in which applications were added

private OpenAPIProvider cachedProvider = null;

// Lazily initialized, use getModuleSelectionConfig() instead
private ModuleSelectionConfig moduleSelectionConfig = null;
@Reference
private ModuleSelectionConfig moduleSelectionConfig;

/**
* The addApplication method is invoked by the {@link ApplicationListener} when it is notified that an application
Expand All @@ -95,13 +116,13 @@ public void addApplication(ApplicationInfo newAppInfo) {

OpenAPIProvider firstProvider = getFirstProvider();

if (getModuleSelectionConfig().useFirstModuleOnly() && firstProvider != null) {
if (moduleSelectionConfig.useFirstModuleOnly() && firstProvider != null) {
if (LoggingUtils.isEventEnabled(tc)) {
Tr.event(this, tc, "Application Processor: useFirstModuleOnly is configured and we already have a module. Not processing. appInfo=" + newAppInfo);
}
mergeDisabledAlerter.setUsingMultiModulesWithoutConfig(firstProvider);
} else {
Collection<OpenAPIProvider> openApiProviders = applicationProcessor.processApplication(newAppInfo, getModuleSelectionConfig());
Collection<OpenAPIProvider> openApiProviders = applicationProcessor.processApplication(newAppInfo, moduleSelectionConfig);

if (!openApiProviders.isEmpty()) {
// If the new application has any providers, invalidate the model cache
Expand Down Expand Up @@ -139,15 +160,15 @@ public void removeApplication(ApplicationInfo removedAppInfo) {
// If the removed application had any providers, invalidate the provider cache
cachedProvider = null;

if (getModuleSelectionConfig().useFirstModuleOnly() && !FrameworkState.isStopping()) {
if (moduleSelectionConfig.useFirstModuleOnly() && !FrameworkState.isStopping()) {
if (LoggingUtils.isEventEnabled(tc)) {
Tr.event(this, tc, "Application Processor: Current OpenAPI application removed, looking for another application to document.");
}

// We just removed the module used for the OpenAPI document and the server is not shutting down.
// We need to find a new module to use if there is one
for (ApplicationRecord app : applications.values()) {
Collection<OpenAPIProvider> providers = applicationProcessor.processApplication(app.info, getModuleSelectionConfig());
Collection<OpenAPIProvider> providers = applicationProcessor.processApplication(app.info, moduleSelectionConfig);
if (!providers.isEmpty()) {
app.providers.addAll(providers);
break;
Expand Down Expand Up @@ -192,9 +213,7 @@ protected void setServerStartPhase2(ServerStartedPhase2 event) {
// Couldn't read this application for some reason, but that means we can't have been able to include modules from it anyway.
}
}
for (String unmatchedInclude : getModuleSelectionConfig().findIncludesNotMatchingAnything(modules)) {
Tr.warning(tc, MessageConstants.OPENAPI_MERGE_UNUSED_INCLUDE_CWWKO1667W, Constants.MERGE_INCLUDE_CONFIG, unmatchedInclude);
}
moduleSelectionConfig.sendWarningsForIncludesNotMatchingAnything(modules);
}
}

Expand Down Expand Up @@ -254,19 +273,6 @@ private List<OpenAPIProvider> getProvidersToMerge() {
}
}

/**
* Thread safety: Caller must hold lock on {@code this}
*
* @return the module selection config
*/
private ModuleSelectionConfig getModuleSelectionConfig() {
if (moduleSelectionConfig == null) {
// Lazy initialization to avoid calling getConfig() before Config is ready
moduleSelectionConfig = ModuleSelectionConfig.fromConfig(ConfigProvider.getConfig(ApplicationRegistryImpl.class.getClassLoader()));
}
return moduleSelectionConfig;
}

/**
* Thread safety: Caller must hold lock on {@code this}
*
Expand All @@ -282,6 +288,18 @@ private OpenAPIProvider getFirstProvider() {
return null;
}

@Override
public synchronized void processConfigUpdate() {
Map<String, ApplicationRecord> oldApps = applications;
applications = new LinkedHashMap<>();
for (ApplicationRecord record : oldApps.values()) {
//Add application uses config to decide if it creates and registers any providers in ApplicationInfo
//Rather than map from the old state to the new state when the config changes, KISS and start again.
addApplication(record.info);
}
cachedProvider = null;
Comment on lines +293 to +300
Copy link
Member

@Azquelt Azquelt Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, we use synchronized (this) in the method body rather than synchronized in the signature so that the generated trace is outside the synchronized block, making it easier to debug lock contention.

Since addApplication can take a while to complete, I think we should do that here.

}

private static class ApplicationRecord {
public ApplicationRecord(ApplicationInfo info) {
this.info = info;
Expand All @@ -291,4 +309,18 @@ public ApplicationRecord(ApplicationInfo info) {
private final List<OpenAPIProvider> providers = new ArrayList<>();
}

@Override
public int compareTo(OpenAPIAppConfigListener o) {
if (this == o || this.equals(o)) {
return 0;
} else {
return this.getConfigListenerPriority() - o.getConfigListenerPriority();
}
}

@Override
public int getConfigListenerPriority() {
return 2;
}
Comment on lines +322 to +324
Copy link
Member

@Azquelt Azquelt Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment that this is to ensure we're called after the ModuleSelectionConfig


}
Loading