added a first version of java doc for the templating module

This commit is contained in:
Sheldan
2020-05-11 20:46:14 +02:00
parent e89c3b8796
commit 70428e6e03
19 changed files with 283 additions and 10 deletions

View File

@@ -12,6 +12,9 @@ import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;
import java.io.IOException;
import java.util.Locale;
/**
* Configuration bean used to provide the {@link Configuration} bean to the spring context.
*/
@org.springframework.context.annotation.Configuration
public class FreemarkerConfiguration {
@@ -24,6 +27,12 @@ public class FreemarkerConfiguration {
@Autowired
private InstantMethod instantMethod;
/**
* Creates a {@link Configuration} bean with the appropriate configuration which includes:
* The correct compatibility version and the provided formatter methods to be used in the templates.
* The encoding of the templates is set to UTF-8.
* @return A configured {@link Configuration} bean according to the configuration
*/
@Bean
public Configuration freeMarkerConfiguration() throws IOException, TemplateException {
FreeMarkerConfigurationFactory factory = new FreeMarkerConfigurationFactory();

View File

@@ -16,6 +16,10 @@ import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
/**
* Loads the available templates from the class path and uploads them to the database, overriding existing templates in the process.
* This will load all *.ftl files at any level within a folder named 'templates' in the resources folder.
*/
@Component
@Slf4j
public class TemplateSeedDataLoader {
@@ -26,6 +30,10 @@ public class TemplateSeedDataLoader {
@Autowired
private TemplateManagementService service;
/**
* Is executed when the spring context is started, this will load all templates from the class path and
* store them in the database overriding the existing ones in the process.
*/
@EventListener
public void handleContextRefreshEvent(ContextRefreshedEvent ctxStartEvt) {
log.info("Updating templates.");

View File

@@ -11,6 +11,10 @@ import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
/**
* Loads the the template from the database to be used by Freemarker. This bean is also used when the templates within
* templates are used.
*/
@Component
public class DatabaseTemplateLoader implements TemplateLoader {
@@ -20,6 +24,11 @@ public class DatabaseTemplateLoader implements TemplateLoader {
@Autowired
private TemplateManagementService templateManagementService;
/**
* Loads the content of the template object
* @param s The key of the template to load
* @return The template loaded from the database
*/
@Override
public Object findTemplateSource(String s) throws IOException {
return templateManagementService.getTemplateByKey(s);
@@ -36,6 +45,12 @@ public class DatabaseTemplateLoader implements TemplateLoader {
}
}
/**
* Retrieves the content of the template from the retrieved {@link Template} object
* @param o The retrieved {@link Template} object from the database
* @param s The encoding of the object
* @return The content of the template as a String reader
*/
@Override
public Reader getReader(Object o, String s) throws IOException {
return new StringReader(((Template) o).getContent());

View File

@@ -12,12 +12,23 @@ import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
/**
* Method used to format the {@link Duration} object, as its not natively supported by Freemarker.
* This method only accepts a single {@link Duration} object as the first parameter.
*/
@Component
public class DurationMethod implements TemplateMethodModelEx {
@Autowired
private TemplateService service;
/**
* This method expects a single Duration object in the list of arguments. It will throw a {@link TemplateModelException}
* otherwise
* @param arguments The parameters passed to this method, should be only a single duration.
* @return The string representation of the {@link Duration} object
* @throws TemplateModelException
*/
@Override
public Object exec(List arguments) throws TemplateModelException {
if (arguments.size() != 1) {
@@ -30,6 +41,7 @@ public class DurationMethod implements TemplateMethodModelEx {
Duration duration = (Duration) wrappedObject;
StringBuilder stringBuilder = new StringBuilder();
// upgrading to java 9 makes this nicer
// todo refactor to use a single template, instead of multiple ones
long days = duration.toDays();
if(days > 0) {
stringBuilder.append(service.renderTemplate("day", getParam(days)));
@@ -51,6 +63,11 @@ public class DurationMethod implements TemplateMethodModelEx {
return stringBuilder.toString();
}
/**
* Creates the parameter passed to the template for rendering the single time unit template.
* @param value
* @return
*/
private HashMap<String, Object> getParam(Long value) {
HashMap<String, Object> params = new HashMap<>();
params.put("amount", value);

View File

@@ -11,15 +11,23 @@ import org.springframework.stereotype.Component;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
/**
* Formats the passed {@link Instant} object with the given Formatter. The format will be directly passed to {@link DateTimeFormatter}.
*/
@Component
public class InstantMethod implements TemplateMethodModelEx {
@Autowired
private TemplateService service;
/**
* Renders the given {@link Instant} object with the given String. Internally {@link DateTimeFormatter} will be used.
* @param arguments The list of arguments, first element must be an {@link Instant} and the second one must be a {@link String}.
* @return The formatted {@link Instant} as a string.
* @throws TemplateModelException If there are less or more arguments in the list and if the first element is not a {@link Instant}.
*/
@Override
public Object exec(List arguments) throws TemplateModelException {
if (arguments.size() != 2) {

View File

@@ -4,9 +4,22 @@ package dev.sheldan.abstracto.templating.model;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
/**
* The container class used to deserialize the embed configuration for the author in {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
@Getter
@Setter
public class EmbedAuthor {
/**
* The name used in the {@link net.dv8tion.jda.api.entities.MessageEmbed} author
*/
private String name;
/**
* The URL used in the {@link net.dv8tion.jda.api.entities.MessageEmbed} author
*/
private String url;
/**
* The picture used as the avatar of the author in {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private String avatar;
}

View File

@@ -3,9 +3,22 @@ package dev.sheldan.abstracto.templating.model;
import lombok.Getter;
import lombok.Setter;
@Setter @Getter
/**
* The container class used to deserialize the embed configuration for the color in {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
@Setter
@Getter
public class EmbedColor {
/**
* The red part of RGB
*/
private Integer r;
/**
* The green part of RGB
*/
private Integer g;
/**
* The blue part of RGB
*/
private Integer b;
}

View File

@@ -6,16 +6,51 @@ import lombok.Setter;
import java.time.OffsetDateTime;
import java.util.List;
@Getter @Setter
/**
* The whole container object used to deserialize the whole embed configuration
* https://raw.githubusercontent.com/DV8FromTheWorld/JDA/assets/assets/docs/embeds/07-addField.png
*/
@Getter
@Setter
public class EmbedConfiguration {
/**
* The {@link EmbedAuthor} object holding the configuration for the author of the {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private EmbedAuthor author;
/**
* The {@link EmbedTitle} object holding the configuration for the title in the {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private EmbedTitle title;
/**
* The {@link EmbedColor} object holding the configuration for the color in the {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private EmbedColor color;
/**
* The description which is going to be used in the {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private String description;
/**
* The link to the image used as a thumbnail in the {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private String thumbnail;
/**
* The link to the image used as the image in the {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private String imageUrl;
/**
* The collection containing all the objects containing the configuration for the fields in the {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private List<EmbedField> fields;
/**
* The {@link EmbedFooter} object holding the configuration for the footer in {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private EmbedFooter footer;
/**
* Thhe {@link OffsetDateTime} object used as the time stamp in the {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
private OffsetDateTime timeStamp;
/**
* The message which is posted along the {@link net.dv8tion.jda.api.entities.MessageEmbed} as a normal message.
*/
private String additionalMessage;
}

View File

@@ -3,9 +3,23 @@ package dev.sheldan.abstracto.templating.model;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
/**
* The container class used to deserialize the embed configuration for a field in {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
@Getter
@Setter
public class EmbedField {
/**
* The name of the field to be set, must not be null or empty
*/
private String name;
/**
* The value of the field to be set, must not be null or empty
*/
private String value;
/**
* Whether or not the field should be rendered inline within the {@link net.dv8tion.jda.api.entities.MessageEmbed}.
* This means, if multiple fields can be put on the same height in the {@link net.dv8tion.jda.api.entities.MessageEmbed} this will be done by discord.
*/
private Boolean inline;
}

View File

@@ -3,8 +3,18 @@ package dev.sheldan.abstracto.templating.model;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
/**
* The container object used to deserialize the embed configuration for the footer in the {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
@Getter
@Setter
public class EmbedFooter {
/**
* The text which is going to be used as the footer text
*/
private String text;
/**
* The link to the image which is going to be used as the icon of the footer
*/
private String icon;
}

View File

@@ -3,8 +3,18 @@ package dev.sheldan.abstracto.templating.model;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
/**
* The container class used to deserialize the embed configuration used in the title in {@link net.dv8tion.jda.api.entities.MessageEmbed}
*/
@Getter
@Setter
public class EmbedTitle {
/**
* The text which is going to be used as the title of the embed
*/
private String title;
/**
* The link which is used when clicking on the title of the embed
*/
private String url;
}

View File

@@ -1,9 +1,12 @@
package dev.sheldan.abstracto.templating.loading;
package dev.sheldan.abstracto.templating.repository;
import dev.sheldan.abstracto.templating.model.database.Template;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* Repository used to load the templates from the database.
*/
@Repository
public interface TemplateRepository extends JpaRepository<Template, String> {
}

View File

@@ -19,6 +19,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
/**
* Bean used to render a template, identified by a key, with the passed model.
*/
@Slf4j
@Component
public class TemplateServiceBean implements TemplateService {
@@ -30,12 +33,29 @@ public class TemplateServiceBean implements TemplateService {
private Gson gson;
/**
* Formats the passed passed count with the embed used for formatting pages.
* @param count The index of the page you want formated.
* @return The rendered template as a string object
*/
private String getPageString(Integer count) {
HashMap<String, Object> params = new HashMap<>();
params.put("count", count);
return renderTemplateWithMap("embed_page_count", params);
}
/**
* Retrieves the key which gets suffixed with '_embed' and this retrives the embed configuration. This configuration is then rendered
* and deserialized with GSON into a {@link EmbedConfiguration} object. This object is then rendered into a {@link MessageToSend} and returned.
* If the individual element do not fit in an embed, for example, if the field count is to high, another embed will be created in the {@link MessageToSend} object.
* If multiple embeds are necessary to provide what the {@link EmbedConfiguration} wanted, this method will automatically set the footer of the additional {@link MessageEmbed}
* with a formatted page count.
* This method will to try its best to provided a message which can be handled by discord without rejecting it. Besides that, the content from the rendered template, will be passed
* into the {@link EmbedBuilder} directly.
* @param key The key of the embed template to be used for rendering.
* @param model The model providing the properties to be used for rendering
* @return The {@link MessageToSend} object which is properly split up in order to be send to discord.
*/
@Override
public MessageToSend renderEmbedTemplate(String key, Object model) {
String embedConfig = this.renderTemplate(key + "_embed", model);
@@ -100,6 +120,12 @@ public class TemplateServiceBean implements TemplateService {
.build();
}
/**
* Enlarges the passed list of builders, if the passed index is not yet available within the list.
* When a new builder is needed, this will automatically set the footer with a page indicator.
* @param builders The current list of {@link EmbedBuilder} builders used.
* @param neededIndex The desired index in the list which should be available for using.
*/
private void extendIfNecessary(List<EmbedBuilder> builders, double neededIndex) {
if(neededIndex > builders.size() - 1) {
for (int i = builders.size(); i < neededIndex + 1; i++) {
@@ -110,6 +136,12 @@ public class TemplateServiceBean implements TemplateService {
}
}
/**
* Renders the template identified by the key with the passed {@link HashMap}
* @param key The key of the template to be rendered.
* @param parameters The {@link HashMap} to be used as the parameters for the template
* @return The rendered template as a string
*/
@Override
public String renderTemplateWithMap(String key, HashMap<String, Object> parameters) {
try {
@@ -120,6 +152,12 @@ public class TemplateServiceBean implements TemplateService {
}
}
/**
* Renders the template identified by the key with the passed object as model
* @param key The key of the template to be rendered
* @param model The object containing the model to be used in the template
* @return The rendered template as a string
*/
@Override
public String renderTemplate(String key, Object model) {
try {

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.templating.service.management;
import dev.sheldan.abstracto.templating.loading.TemplateRepository;
import dev.sheldan.abstracto.templating.repository.TemplateRepository;
import dev.sheldan.abstracto.templating.model.database.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -8,6 +8,10 @@ import org.springframework.stereotype.Component;
import java.time.Instant;
/**
* ManagementService bean used to retrieve the templates by key from the database.
* This class uses the {@link TemplateRepository} bean to laod the {@link Template} objects.
*/
@Component
@Slf4j
public class TemplateManagementServiceBean implements TemplateManagementService {
@@ -22,7 +26,7 @@ public class TemplateManagementServiceBean implements TemplateManagementService
@Override
public boolean templateExists(String key) {
return getTemplateByKey(key) != null;
return repository.existsById(key);
}
@Override