Skip to content

Commit

Permalink
Merge pull request #877 from altro3/custumize_templates
Browse files Browse the repository at this point in the history
Add ability to override UI templates
  • Loading branch information
graemerocher authored Dec 7, 2022
2 parents 2656310 + 8d1582c commit 4b82440
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ abstract class AbstractViewConfig {
protected String jsUrl = "";
protected String finalUrlPrefix;
protected String resourcesContextPath = "/res";
protected String templatePath;
protected boolean isDefaultJsUrl = true;
protected boolean withFinalUrlPrefixCache = true;
protected Map<String, Object> options = new HashMap<>();
Expand All @@ -61,6 +62,12 @@ protected AbstractViewConfig(String prefix) {

protected abstract List<String> getResources();

public String getTemplatePath() {
return templatePath;
}

public abstract String render(String template, VisitorContext context);

/**
* Adds an option.
*
Expand Down Expand Up @@ -143,6 +150,11 @@ static <T extends AbstractViewConfig> T fromProperties(T cfg, Map<String, Object
}
}

String templatePath = properties.get(cfg.prefix + "template.path");
if (StringUtils.isNotEmpty(templatePath)) {
cfg.templatePath = templatePath;
}

cfg.options.putAll(defaultOptions);
properties.entrySet().stream().filter(entry -> entry.getKey().startsWith(cfg.prefix))
.forEach(cfg::addAttribute);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,17 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;

import io.micronaut.core.io.scan.ClassPathResourceLoader;
import io.micronaut.core.io.scan.DefaultClassPathResourceLoader;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.inject.visitor.VisitorContext;
import io.micronaut.openapi.visitor.OpenApiApplicationVisitor;
import io.micronaut.openapi.visitor.Utils;

/**
* OpenApi view configuration for Swagger-ui, ReDoc and RapiDoc.
Expand Down Expand Up @@ -257,21 +261,77 @@ private String readTemplateFromClasspath(String templateName) throws IOException
StringBuilder buf = new StringBuilder(1024);
ClassLoader classLoader = getClass().getClassLoader();
try (InputStream in = classLoader.getResourceAsStream(templateName);
BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))
) {
String line;
while ((line = r.readLine()) != null) {
buf.append(line).append('\n');
}
return buf.toString();
return readFile(reader);
} catch (Exception e) {
throw new IOException("Fail to load " + templateName, e);
}
}

private void render(Renderer renderer, Path outputDir, String templateName, VisitorContext context) throws IOException {
String template = readTemplateFromClasspath(templateName);
template = renderer.render(template, context);
private String readTemplateFromCustomPath(String customPathStr, VisitorContext context) throws IOException {
String projectDir = StringUtils.EMPTY_STRING;
Path projectPath = Utils.getProjectPath(context);
if (projectPath != null) {
projectDir = projectPath.toString().replaceAll("\\\\", "/");
}
if (customPathStr.startsWith("project:")) {
customPathStr = customPathStr.replace("project:", projectDir);
} else if (!customPathStr.startsWith("file:") && !customPathStr.startsWith("classpath:")) {
if (!projectDir.endsWith(SLASH)) {
projectDir += SLASH;
}
if (customPathStr.startsWith(SLASH)) {
customPathStr = customPathStr.substring(1);
}
customPathStr = projectDir + customPathStr;
} else if (customPathStr.startsWith("file:")) {
customPathStr = customPathStr.substring(5);
} else if (customPathStr.startsWith("classpath:")) {
ClassPathResourceLoader resourceLoader = new DefaultClassPathResourceLoader(getClass().getClassLoader());
Optional<InputStream> inOpt = resourceLoader.getResourceAsStream(customPathStr);
if (!inOpt.isPresent()) {
throw new IOException("Fail to load " + customPathStr);
}
try (InputStream in = inOpt.get();
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))
) {
return readFile(reader);
} catch (IOException e) {
throw new IOException("Fail to load " + customPathStr, e);
}
}

Path templatePath = OpenApiApplicationVisitor.resolve(context, Paths.get(customPathStr));
if (!Files.isReadable(templatePath)) {
throw new IOException("Can't read file " + customPathStr);
}
try (BufferedReader reader = Files.newBufferedReader(templatePath)) {
return readFile(reader);
} catch (IOException e) {
throw new IOException("Fail to load " + customPathStr, e);
}
}

private String readFile(BufferedReader reader) throws IOException {
StringBuilder buf = new StringBuilder(1024);
String line;
while ((line = reader.readLine()) != null) {
buf.append(line).append('\n');
}
return buf.toString();
}

private void render(AbstractViewConfig cfg, Path outputDir, String templateName, VisitorContext context) throws IOException {

String template;
if (StringUtils.isEmpty(cfg.templatePath)) {
template = readTemplateFromClasspath(templateName);
} else {
template = readTemplateFromCustomPath(cfg.templatePath, context);
}

template = cfg.render(template, context);
template = replacePlaceHolder(template, "specURL", getSpecURL(context), "");
template = replacePlaceHolder(template, "title", getTitle(), "");
if (!Files.exists(outputDir)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,9 @@ protected Function<String, Object> getConverter(String key) {
protected List<String> getResources() {
return RESOURCE_FILES;
}

@Override
public String render(String template, VisitorContext context) {
throw new IllegalStateException("RapiPDF doesn't support render");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
*
* @author croudet
*/
final class RapidocConfig extends AbstractViewConfig implements Renderer {
final class RapidocConfig extends AbstractViewConfig {

public static final String RAPIDOC_PREFIX = "rapidoc.";
private static final String DEFAULT_RAPIDOC_JS_PATH = OpenApiViewConfig.RESOURCE_DIR + "/";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*
* @author croudet
*/
final class RedocConfig extends AbstractViewConfig implements Renderer {
final class RedocConfig extends AbstractViewConfig {

private static final String DEFAULT_REDOC_JS_PATH = OpenApiViewConfig.RESOURCE_DIR + "/";

Expand Down
36 changes: 0 additions & 36 deletions openapi/src/main/java/io/micronaut/openapi/view/Renderer.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
*
* @author croudet
*/
final class SwaggerUIConfig extends AbstractViewConfig implements Renderer {
final class SwaggerUIConfig extends AbstractViewConfig {

private static final String DEFAULT_SWAGGER_JS_PATH = OpenApiViewConfig.RESOURCE_DIR + "/";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public AnnProcessorEnvironment(ApplicationContextConfiguration configuration, Vi

boolean isEnabled = context != null ? context.get(MICRONAUT_ENVIRONMENT_ENABLED, Boolean.class).orElse(false) : false;
if (isEnabled) {
Path projectPath = context.getProjectDir().orElse(Utils.isTestMode() ? Paths.get(System.getProperty("user.dir")) : null);
Path projectPath = Utils.getProjectPath(context);
if (projectPath != null) {
projectDir = "file:" + projectPath.toString().replaceAll("\\\\", "/");
projectResourcesPath = projectDir + (projectDir.endsWith("/") ? StringUtils.EMPTY_STRING : "/") + "src/main/resources/";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ private void mergeAdditionalSwaggerFiles(ClassElement element, VisitorContext co
}
}

private static Path resolve(VisitorContext context, Path path) {
public static Path resolve(VisitorContext context, Path path) {
if (!path.isAbsolute() && context != null) {
Optional<Path> projectDir = context.getProjectDir();
if (projectDir.isPresent()) {
Expand Down
7 changes: 7 additions & 0 deletions openapi/src/main/java/io/micronaut/openapi/visitor/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import java.io.File;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand All @@ -30,6 +32,7 @@
import io.micronaut.core.convert.ArgumentConversionContext;
import io.micronaut.core.convert.DefaultConversionService;
import io.micronaut.core.util.CollectionUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.core.value.PropertyResolver;
import io.micronaut.http.MediaType;
import io.micronaut.inject.ast.ClassElement;
Expand Down Expand Up @@ -62,6 +65,10 @@ public final class Utils {
private Utils() {
}

public static Path getProjectPath(VisitorContext context) {
return context.getProjectDir().orElse(Utils.isTestMode() ? Paths.get(System.getProperty("user.dir")) : null);
}

/**
* @return An Instance of sdefault {@link PropertyPlaceholderResolver} to resolve placeholders.
*/
Expand Down

0 comments on commit 4b82440

Please sign in to comment.