io.micronaut.openapi.view.AbstractViewConfig Maven / Gradle / Ivy
/*
* Copyright 2017-2023 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.openapi.view;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.util.StringUtils;
import io.micronaut.core.util.Toggleable;
import io.micronaut.inject.visitor.VisitorContext;
import io.micronaut.openapi.visitor.ConfigUtils;
import io.micronaut.openapi.visitor.Pair;
import io.micronaut.openapi.visitor.group.GroupProperties;
import io.micronaut.openapi.visitor.group.OpenApiInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import static io.micronaut.openapi.visitor.ConfigUtils.getGroupProperties;
import static io.micronaut.openapi.visitor.OpenApiConfigProperty.MICRONAUT_OPENAPI_CONTEXT_SERVER_PATH;
import static io.micronaut.openapi.visitor.StringUtil.PLACEHOLDER_POSTFIX;
import static io.micronaut.openapi.visitor.StringUtil.PLACEHOLDER_PREFIX;
import static io.micronaut.openapi.visitor.StringUtil.QUOTE;
import static io.micronaut.openapi.visitor.StringUtil.SLASH;
/**
* Abstract View Config.
*
* @author croudet
*/
public abstract class AbstractViewConfig implements Toggleable {
protected String prefix;
protected String jsUrl = StringUtils.EMPTY_STRING;
protected String specUrl;
/**
* URL prefix from config properties.
*/
protected String urlPrefix;
/**
* URL prefix for templates and resources.
*/
protected String fullUrlPrefix;
protected String resourcesContextPath = "/res";
protected String templatePath;
protected boolean isDefaultJsUrl = true;
protected boolean copyResources = true;
protected boolean withFinalUrlPrefixCache = true;
protected String primaryName;
protected Boolean withUrls;
protected List urls = new ArrayList<>();
protected Map options = new HashMap<>();
@Nullable
protected Map, OpenApiInfo> openApiInfos;
/**
* An AbstractViewConfig.
*
* @param prefix The configuration key prefix.
* @param openApiInfos Information about all generated openAPI files.
*/
protected AbstractViewConfig(String prefix, Map, OpenApiInfo> openApiInfos) {
this.prefix = prefix;
this.openApiInfos = openApiInfos;
}
/**
* Returns the converter associated with the key.
*
* @param key A key.
*
* @return A converter or null.
*/
protected abstract Function getConverter(String key);
protected abstract List getResources();
/**
* Get template path.
*
* @return template path
*/
public String getTemplatePath() {
return templatePath;
}
public abstract String render(String template, @Nullable VisitorContext context);
/**
* Adds an option.
*
* @param entry The user specified entry.
*/
protected void addAttribute(Map.Entry entry) {
String key = entry.getKey().substring(prefix.length());
Function converter = getConverter(key);
if (converter != null) {
options.put(key, converter.apply(entry.getValue()));
}
}
/**
* Converts to html attributes.
*
* @return A String.
*/
protected String toHtmlAttributes() {
return options.entrySet().stream()
.map(e -> e.getKey() + "=\"" + e.getValue() + '"')
.collect(Collectors.joining(" "));
}
/**
* Calculate final URL prefix for resources.
*
* @param rendererType render type
* @param context visitor context
* @return final URL prefix for resources
*/
protected String getFinalUrlPrefix(OpenApiViewConfig.RendererType rendererType, VisitorContext context) {
if (fullUrlPrefix != null && withFinalUrlPrefixCache) {
return fullUrlPrefix;
}
// process micronaut.openapi.server.context.path
String serverContextPath = ConfigUtils.getConfigProperty(MICRONAUT_OPENAPI_CONTEXT_SERVER_PATH, context);
if (serverContextPath == null) {
serverContextPath = StringUtils.EMPTY_STRING;
}
String finalUrl = serverContextPath.startsWith(SLASH) ? serverContextPath : SLASH + serverContextPath;
if (!finalUrl.endsWith(SLASH)) {
finalUrl += SLASH;
}
// process micronaut.server.context-path
String contextPath = ConfigUtils.getServerContextPath(context);
finalUrl += contextPath.startsWith(SLASH) ? contextPath.substring(1) : contextPath;
if (!finalUrl.endsWith(SLASH)) {
finalUrl += SLASH;
}
urlPrefix = finalUrl;
// standard path
finalUrl += rendererType.getTemplatePath();
finalUrl += finalUrl.endsWith(SLASH) ? resourcesContextPath.substring(1) : resourcesContextPath;
if (!finalUrl.endsWith(SLASH)) {
finalUrl += SLASH;
}
fullUrlPrefix = finalUrl;
return finalUrl;
}
/**
* Builds and parse a View Config.
*
* @param A View config type.
* @param cfg A View config.
* @param defaultOptions The default options.
* @param properties The options to parse.
* @param rendererType The render type.
* @param context Visitor context.
*
* @return A View config.
*/
static T fromProperties(T cfg, Map defaultOptions, Map properties, OpenApiViewConfig.RendererType rendererType, VisitorContext context) {
String copyResources = properties.get(cfg.prefix + "copy-resources");
if (StringUtils.isNotEmpty(copyResources) && "false".equalsIgnoreCase(copyResources)) {
cfg.copyResources = false;
}
cfg.withUrls = cfg.openApiInfos != null && (cfg.openApiInfos.size() > 1 || cfg.openApiInfos.get(Pair.NULL_STRING_PAIR) == null);
if (cfg.withUrls) {
String primaryName = null;
var urls = new ArrayList();
for (OpenApiInfo openApiInfo : cfg.openApiInfos.values()) {
String groupName = openApiInfo.getGroupName();
String version = openApiInfo.getVersion();
if (StringUtils.isEmpty(groupName) && StringUtils.isEmpty(version)) {
continue;
}
if (StringUtils.isEmpty(groupName)) {
groupName = version;
}
GroupProperties groupProperties = getGroupProperties(groupName, context);
if (groupProperties != null) {
if (groupProperties.getDisplayName() != null) {
groupName = groupProperties.getDisplayName();
}
if (groupProperties.getPrimary() != null && groupProperties.getPrimary()) {
primaryName = groupName;
}
}
cfg.getFinalUrlPrefix(OpenApiViewConfig.RendererType.SWAGGER_UI, context);
String groupUrl = cfg.urlPrefix + (!cfg.urlPrefix.endsWith(SLASH) ? "/swagger/" : "swagger/") + openApiInfo.getFilename();
urls.add(new OpenApiUrl(groupUrl, groupName));
}
cfg.urls = urls;
if (primaryName != null) {
cfg.primaryName = primaryName;
}
} else {
String specUrl = properties.get(cfg.prefix + "spec.url");
if (specUrl != null) {
String filenameFromContext = null;
if (context != null && cfg.openApiInfos != null) {
filenameFromContext = cfg.openApiInfos.get(Pair.NULL_STRING_PAIR).getFilename();
}
cfg.specUrl = specUrl.replace(PLACEHOLDER_PREFIX + "filename" + PLACEHOLDER_POSTFIX,
filenameFromContext != null ? filenameFromContext : StringUtils.EMPTY_STRING);
}
}
String jsUrl = properties.get(cfg.prefix + "js.url");
if (StringUtils.isNotEmpty(jsUrl)) {
cfg.jsUrl = jsUrl;
cfg.isDefaultJsUrl = false;
} else {
String resourcesContextPath = properties.get(cfg.prefix + "resources.context.path");
if (StringUtils.isNotEmpty(resourcesContextPath)) {
cfg.resourcesContextPath = resourcesContextPath.startsWith(SLASH) ? resourcesContextPath : SLASH + resourcesContextPath;
}
}
String templatePath = properties.get(cfg.prefix + "template.path");
if (StringUtils.isNotEmpty(templatePath)) {
cfg.templatePath = templatePath;
}
cfg.options.putAll(defaultOptions);
for (var entry : properties.entrySet()) {
if (entry.getKey().startsWith(cfg.prefix)) {
cfg.addAttribute(entry);
}
}
return cfg;
}
/**
* Get urls for resources.
*
* @return urls
*/
public List getUrls() {
return urls;
}
/**
* Converts to a Boolean.
*
* @param v The input.
*
* @return A Boolean.
*/
static Object asBoolean(String v) {
return Boolean.valueOf(v);
}
/**
* Converts to an Integer.
*
* @param v The input.
*
* @return An Integer.
*/
static Object asInt(String v) {
return Integer.valueOf(v);
}
/**
* Converts to a String.
*
* @param v The input.
*
* @return A String.
*/
static Object asString(String v) {
return v;
}
/**
* Converts to a quoted String.
*
* @param v The input.
*
* @return A quoted String.
*/
static Object asQuotedString(String v) {
return v == null ? null : QUOTE + v + QUOTE;
}
/**
* Converts to an enum.
*
* @param An Enum class.
*
* @author croudet
*/
static class EnumConverter> implements Function {
private final Class type;
/**
* EnumConverter.
*
* @param type An Enum type.
*/
EnumConverter(Class type) {
this.type = type;
}
/**
* Converts to an Enum.
*/
@Override
public Object apply(String v) {
return v == null ? null : Enum.valueOf(type, v.toUpperCase(Locale.US));
}
}
/**
* URL and resource name.
*
* @param url url
* @param name name
*/
public record OpenApiUrl(String url, String name) {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy