package core.framework.impl.web.site;
import core.framework.api.util.Exceptions;
import core.framework.api.util.Files;
import core.framework.api.util.Maps;
import core.framework.api.util.StopWatch;
import core.framework.api.web.site.WebDirectory;
import core.framework.impl.template.CDNManager;
import core.framework.impl.template.HTMLTemplate;
import core.framework.impl.template.HTMLTemplateBuilder;
import core.framework.impl.template.TemplateContext;
import core.framework.impl.template.source.FileTemplateSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Map;
/**
* @author neo
*/
public class TemplateManager {
public final CDNManager cdnManager = new CDNManager();
public final Map<String, Map<String, HTMLTemplate>> templates = Maps.newConcurrentHashMap(); // path->language->template
private final MessageImpl message;
private final Logger logger = LoggerFactory.getLogger(TemplateManager.class);
private final Map<String, Instant> templateLastModifiedTimes = Maps.newConcurrentHashMap();
private final WebDirectory webDirectory;
public TemplateManager(WebDirectory webDirectory, MessageImpl message) {
this.webDirectory = webDirectory;
this.message = message;
}
public String process(String templatePath, Object model, String language) {
StopWatch watch = new StopWatch();
try {
HTMLTemplate template = get(templatePath, model.getClass(), language);
TemplateContext context = new TemplateContext(model, cdnManager);
return template.process(context);
} finally {
logger.debug("process, templatePath={}, elapsedTime={}", templatePath, watch.elapsedTime());
}
}
public void add(String templatePath, Class<?> modelClass) {
StopWatch watch = new StopWatch();
try {
Map<String, HTMLTemplate> previous = templates.putIfAbsent(templatePath, load(templatePath, modelClass));
if (previous != null) throw Exceptions.error("template was registered, templatePath={}", templatePath);
if (webDirectory.localEnv) {
Path path = webDirectory.path(templatePath);
templateLastModifiedTimes.put(templatePath, Files.lastModified(path));
}
} finally {
logger.info("add, templatePath={}, modelClass={}, elapsedTime={}", templatePath, modelClass.getCanonicalName(), watch.elapsedTime());
}
}
private HTMLTemplate get(String templatePath, Class<?> modelClass, String language) {
Map<String, HTMLTemplate> templates = this.templates.get(templatePath);
if (templates == null)
throw Exceptions.error("template is not registered, please use site().template() to add template, templatePath={}", templatePath);
if (webDirectory.localEnv) {
Path path = webDirectory.path(templatePath);
if (Files.lastModified(path).isAfter(templateLastModifiedTimes.get(templatePath))) {
templateLastModifiedTimes.put(templatePath, Files.lastModified(path)); // put modified time first, then template, for zero cost to handle local threading
templates = load(templatePath, modelClass);
this.templates.put(templatePath, templates);
}
}
String targetLanguage = language == null ? MessageImpl.DEFAULT_LANGUAGE : language;
HTMLTemplate template = templates.get(targetLanguage);
if (template == null) throw Exceptions.error("language is not defined, please check site().message(), language={}", targetLanguage);
return template;
}
private Map<String, HTMLTemplate> load(String templatePath, Class<?> modelClass) {
HTMLTemplateBuilder builder = new HTMLTemplateBuilder(new FileTemplateSource(webDirectory.root(), templatePath), modelClass);
builder.cdn = cdnManager;
Map<String, HTMLTemplate> templates = Maps.newHashMap();
for (String language : message.languages) {
builder.message = key -> message.get(key, language);
HTMLTemplate htmlTemplate = builder.build();
templates.put(language, htmlTemplate);
}
return templates;
}
}