![JAR search and dependency download from the Maven repository](/logo.png)
guru.nidi.raml.doc.st.Generator Maven / Gradle / Ivy
/*
* Copyright (C) 2015 Stefan Niederhauser ([email protected])
*
* 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
*
* http://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 guru.nidi.raml.doc.st;
import biz.gabrys.lesscss.compiler.CompilerException;
import biz.gabrys.lesscss.compiler.LessCompilerImpl;
import guru.nidi.loader.Loader;
import guru.nidi.raml.doc.GeneratorConfig;
import guru.nidi.raml.doc.HtmlOptimizer;
import guru.nidi.raml.doc.IoUtil;
import org.raml.model.*;
import org.raml.model.parameter.AbstractParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.stringtemplate.v4.NoIndentWriter;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroupDir;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import static guru.nidi.raml.doc.IoUtil.copy;
/**
*
*/
public class Generator {
private static final Logger log = LoggerFactory.getLogger(Generator.class);
private static final List STATIC_FILES = loadStaticFileList();
private static List loadStaticFileList() {
final List res = new ArrayList<>();
try (final BufferedReader in = new BufferedReader(new InputStreamReader(Generator.class.getResourceAsStream("/guru/nidi/raml/doc/static-files.lst")))) {
String line;
while ((line = in.readLine()) != null) {
res.add(line);
}
} catch (IOException e) {
throw new AssertionError("Could not load static file list: " + e.getMessage());
}
return res;
}
private static final List CUSTOM_FILES = Arrays.asList(
"favicon.ico", "custom-variables.less", "custom-style.less");
private final GeneratorConfig config;
public Generator(GeneratorConfig config) {
this.config = config;
}
public File getTarget(Raml raml) {
return new File(config.getTarget(), filenameFor(raml));
}
private String filenameFor(Raml raml) {
return GeneratorConfig.safeName(raml);
}
public void generate(Raml raml) throws IOException {
generate(Collections.singletonList(raml));
}
public void generate(List ramls) throws IOException {
for (final Raml raml : ramls) {
doGenerate(raml, ramls);
}
}
private void doGenerate(Raml raml, List ramls) throws IOException {
final STGroupDir group = initSTGroup(raml);
if (raml == ramls.get(0)) {
config.getTarget().mkdirs();
if (!config.isForceDelete()) {
checkTargetEmpty(config.getTarget(), ramls);
}
deleteAll(config.getTarget());
generateBase(raml, group);
}
final File target = getTarget(raml);
target.mkdirs();
final ST main = group.getInstanceOf("main/main");
main.add("ramls", ramls);
main.add("baseUri", config.hasFeature(Feature.TRYOUT) ? config.getBaseUri(raml) : null);
main.add("download", config.hasFeature(Feature.DOWNLOAD));
main.add("docson", config.hasFeature(Feature.DOCSON));
set(main, "raml", raml);
render(main, "/main/doc", ".", new File(target, "index.html"));
renderResources(raml, main, target);
renderSecurity(raml, main, target);
}
private void renderSecurity(Raml raml, ST main, File target) throws IOException {
for (Map sss : raml.getSecuritySchemes()) {
for (Map.Entry entry : sss.entrySet()) {
set(main, "param", entry);
final File file = new File(target, "security-scheme/" + entry.getKey() + ".html");
render(main, "/securityScheme/securityScheme", "..", file);
}
}
}
private void renderResources(Raml raml, ST main, File target) throws IOException {
for (Resource resource : new RamlAdaptor().getAllResources(raml)) {
set(main, "param", resource);
final File file = new File(target, "resource" + IoUtil.safePath(resource.getUri()) + ".html");
render(main, "/resource/resource", depth(resource.getUri()), file);
}
}
private void checkTargetEmpty(File target, List ramls) {
for (final File file : target.listFiles()) {
if (!isAllowedInTarget(file, ramls)) {
throw new IllegalStateException("Cannot generate doc in folder '" + target + "' because it is not empty. " +
"Contains " + (file.isDirectory() ? "directory" : "file") + " '" + file.getName() + "'.");
}
}
}
private boolean isAllowedInTarget(File file, List ramls) {
final String name = file.getName();
return "index.html".equals(name) || name.startsWith("@resource") || existsTitle(name, ramls) ||
STATIC_FILES.contains(name) || (STATIC_FILES.contains(name + "/") && file.isDirectory()) ||
(name.endsWith(".css") && STATIC_FILES.contains(name.substring(0, name.length() - 4) + ".less"));
}
private boolean existsTitle(String name, List ramls) {
for (final Raml raml : ramls) {
if (name.equals(filenameFor(raml))) {
return true;
}
}
return false;
}
private void deleteAll(File target) {
for (final File file : target.listFiles()) {
if (file.isDirectory()) {
deleteAll(file);
}
file.delete();
}
}
private STGroupDir initSTGroup(Raml raml) {
final STGroupDir group = loadGroupDir("guru/nidi/raml/doc/st-templates");
group.registerModelAdaptor(Map.class, new EntrySetMapModelAdaptor());
group.registerModelAdaptor(Raml.class, new RamlAdaptor());
group.registerModelAdaptor(Resource.class, new ResourceAdaptor());
group.registerModelAdaptor(Action.class, new ActionAdaptor(raml));
group.registerModelAdaptor(SecuritySchemeDescriptor.class, new SecuritySchemeDescriptorAdaptor());
group.registerModelAdaptor(Response.class, new ResponseAdaptor());
group.registerRenderer(String.class, new StringRenderer(raml, config.getResourceCache()));
group.registerRenderer(AbstractParam.class, new ParamRenderer());
group.registerRenderer(Raml.class, new RamlRenderer());
return group;
}
private void generateBase(Raml raml, STGroupDir group) throws IOException {
copyStaticResources(config.getTarget(), STATIC_FILES);
copyCustomResources(config.getTarget(), CUSTOM_FILES);
transformLessResources(config.getTarget());
final ST index = group.getInstanceOf("main/index");
index.add("firstIndex", filenameFor(raml) + "/index.html");
render(index, new File(config.getTarget(), "index.html"));
}
private void render(ST template, String sub, String relPath, File target) throws IOException {
set(template, "template", sub);
set(template, "relPath", relPath);
render(template, target);
new HtmlOptimizer().optimizeColumnWidths(target);
}
private void render(ST template, File file) throws IOException {
file.getParentFile().mkdirs();
try (final OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), "utf-8")) {
final StringWriter sw = new StringWriter();
template.write(new NoIndentWriter(sw));
out.write(sw.toString());
}
}
private STGroupDir loadGroupDir(String path) {
try {
return new STGroupDir(path, '$', '$');
} catch (IllegalArgumentException e) {
//websphere classloader needs a trailing / to find directories on the classpath
//-> add it to check if it exists, and then remove it
final STGroupDir stGroupDir = new STGroupDir(path + "/", '$', '$');
final String url = stGroupDir.root.toExternalForm();
try {
stGroupDir.root = new URL(url.substring(0, url.length() - 1));
return stGroupDir;
} catch (MalformedURLException me) {
throw new IllegalArgumentException(me);
}
}
}
private void copyStaticResources(File base, List names) throws IOException {
for (String name : names) {
if (!name.endsWith("/")) {
final File file = new File(base, name);
file.getParentFile().mkdirs();
try (final InputStream in = getClass().getResourceAsStream("/guru/nidi/raml/doc/static/" + name);
final FileOutputStream out = new FileOutputStream(file)) {
copy(in, out);
}
}
}
}
private void copyCustomResources(File base, List names) throws IOException {
for (String name : names) {
try (final InputStream in = config.loadCustomization(name);
final FileOutputStream out = new FileOutputStream(new File(base, name))) {
copy(in, out);
log.info("Using custom " + name);
} catch (Loader.ResourceNotFoundException e) {
//ignore
}
}
}
private void transformLessResources(File base) throws IOException {
final LessCompilerImpl compiler = new LessCompilerImpl();
for (File file : base.listFiles()) {
final String name = file.getName();
try {
if (name.endsWith(".less")) {
try (final Writer out = new OutputStreamWriter(new FileOutputStream(new File(file.getParentFile(), name.substring(0, name.length() - 5) + ".css")), "utf-8")) {
out.write(compiler.compile(file));
}
}
} catch (CompilerException e) {
log.error("Problem compiling '" + name + "'\n" + stackTraceWithoutCause(e));
}
}
}
private String stackTraceWithoutCause(Exception e) {
String s = e.toString() + "\n";
for (StackTraceElement traceElement : e.getStackTrace()) {
s += "\tat " + traceElement + "\n";
}
return s;
}
private void set(ST template, String name, Object value) {
template.remove(name);
template.add(name, value);
}
private String depth(String s) {
String res = "";
int pos = -1;
while ((pos = s.indexOf('/', pos + 1)) >= 0) {
res += "../";
}
return res + ".";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy