EmailDraftService.java
package org.ferris.resiste.console.email;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import java.io.StringWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.regex.Pattern;
import javax.annotation.PostConstruct;
import javax.annotation.Priority;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import org.ferris.resiste.console.conf.ConfDirectory;
import static org.ferris.resiste.console.email.EmailDraftEvent.DRAFT_MAP;
import org.ferris.resiste.console.lang.StringUtils;
import org.ferris.resiste.console.rss.RssEntry;
import org.ferris.resiste.console.rss.RssFeed;
import org.ferris.resiste.console.rss.RssImage;
import org.ferris.resiste.console.rss.RssMediaFile;
import org.ferris.resiste.console.text.i18n.LocalizedString;
import org.ferris.resiste.console.text.i18n.LocalizedStringKey;
import org.ferris.resiste.console.util.version.Version;
import org.slf4j.Logger;
/**
*
* @author Michael Remijan mjremijan@yahoo.com @mjremijan
*/
@ApplicationScoped
public class EmailDraftService {
@Inject
protected Logger log;
@Inject
protected Version version;
@Inject
@LocalizedStringKey("EmailDraft.NoTitle")
protected LocalizedString noTitle;
@Inject
@LocalizedStringKey("EmailDraft.NoContents")
protected LocalizedString noContents;
@Inject
@LocalizedStringKey("EmailDraft.NoAuthor")
protected LocalizedString noAuthor;
@Inject
@LocalizedStringKey("EmailDraft.NoDate")
protected LocalizedString noDate;
@Inject
@LocalizedStringKey("EmailDraft.NoLinkHref")
protected LocalizedString noLinkHref;
@Inject
@LocalizedStringKey("EmailDraft.NoLinkText")
protected LocalizedString noLinkText;
@Inject
protected ConfDirectory confDirectory;
private Template subjectTemplate, bodyTemplate;
private Pattern flickrPattern, widthHeightPattern;
@PostConstruct
protected void postConstruct() {
try {
// -------------------- Create a configuration instance
// Create your Configuration instance, and specify if up to what FreeMarker
// version (here 2.3.25) do you want to apply the fixes that are not 100%
// backward-compatible. See the Configuration JavaDoc for details.
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
// Specify the source where the template files come from. Here I set a
// plain directory for it, but non-file-system sources are possible too:
cfg.setDirectoryForTemplateLoading(confDirectory);
// Set the preferred charset template files are stored in. UTF-8 is
// a good choice in most applications:
cfg.setDefaultEncoding("UTF-8");
// Sets how errors will appear.
// During web page *development* TemplateExceptionHandler.HTML_DEBUG_HANDLER is better.
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// Don't log exceptions inside FreeMarker that it will thrown at you anyway:
cfg.setLogTemplateExceptions(false);
// Subject template
subjectTemplate = cfg.getTemplate("rss_email_subject.ftlt");
// Body template
bodyTemplate = cfg.getTemplate("rss_email_body.ftlt");
// Patterns
flickrPattern = Pattern.compile("farm[\\d]+\\.staticflickr.com");
widthHeightPattern = Pattern.compile("(width|height)=[\"]?[\\d]+[\"]?");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected void observeDraftMap(
@Observes @Priority(DRAFT_MAP) EmailDraftEvent evnt
) {
log.info(String.format("ENTER %s", evnt));
List<EmailDraft> drafts
= new LinkedList<>();
List<RssFeed> feeds
= evnt.getFeeds();
feeds.stream().forEach(
sf -> sf.getEntries().stream().forEach(se -> {
EmailDraft ed = new EmailDraft(
renderSubject(sf)
, renderBody(se)
);
// Add to list
drafts.add(ed);
})
);
evnt.setDrafts(drafts);
}
private String renderBody(RssEntry se) {
log.debug("ENTER");
// Title
String title = Optional.ofNullable(StringUtils.trimToNull(se.getTitle())).orElse(noTitle.toString());
title = title.replaceAll("\\n", " ");
title = StringUtils.abbreviate(title, 70);
log.debug(String.format("TITLE = \"%s\"", title));
// Contents
String contents = (se.getContents().length() > 0) ? se.getContents() : noContents.toString();
if (flickrPattern.matcher(contents).find()) {
contents = widthHeightPattern.matcher(contents)
.replaceAll("")
.replaceAll("_m\\.jpg", "_z.jpg")
;
}
// Author
String author = Optional.ofNullable(StringUtils.trimToNull(se.getAuthor())).orElse(noAuthor.toString());
log.debug(String.format("AUTHOR = \"%s\"", author));
// Published date (YYYY, MMMM dd)
String publishedDate
= Optional.ofNullable(se.getPublishedDate()).map(
d -> new SimpleDateFormat("yyyy, MMMM dd").format(d)).orElse(noDate.toString());
log.debug(String.format("PUBLISHED_DATE = \"%s\"", publishedDate));
// Link href
String linkHref
= Optional.ofNullable(StringUtils.trimToNull(se.getLink())).orElse(noLinkHref.toString());
log.debug(String.format("LINK_HREF = \"%s\"", linkHref));
// Link text
String linkText
= Optional.ofNullable(StringUtils.trimToNull(se.getLink())).orElse(noLinkText.toString());
log.debug(String.format("LINK_TEXT = \"%s\"", linkText));
// Project final name
String projectFinalName
= String.format("%s-%s", version.getImplementationTitle(), version.getImplementationVersion());
// Project url
String projectUrl
= version.getImplementationUrl();
// Images
List<RssImage> images
= se.getImages();
// Media files
List<RssMediaFile> mediaFiles
= se.getMediaFiles();
// FeedId
String feedId = se.getFeedId();
// EntryId
String entryId = se.getEntryId();
// Render
Writer out = new StringWriter();
try {
Map<String, Object> root = new HashMap<>();
root.put("contents", contents);
root.put("author", author);
root.put("publishedDate", publishedDate);
root.put("title", title);
root.put("linkHref", linkHref);
root.put("linkText", linkText);
root.put("projectFinalName", projectFinalName);
root.put("projectUrl", projectUrl);
root.put("images", images);
root.put("mediaFiles", mediaFiles);
root.put("feedId", feedId);
root.put("entryId", entryId);
bodyTemplate.process(root, out);
out.flush();
} catch (Exception ex) {
throw new RuntimeException(
String.format("Problem rendering the email body")
, ex
);
}
log.debug(String.format("RENERED = %n%s", out.toString()));
return out.toString();
}
private String renderSubject(RssFeed sf) {
log.debug("ENTER");
// Title
String title = Optional.ofNullable(StringUtils.trimToNull(sf.getTitle())).orElse(noTitle.toString());
log.debug(String.format("TITLE = \"%s\"", title));
// UUID (Universally Unique Identifier) has a fixed length of 36 characters, including hyphens
// 15951b5b-aff7-468e-8c32-095e0adba8c0
String uuidPart = UUID.randomUUID().toString().substring(30);
// Subject
String subject = StringUtils.abbreviate(title, 45);
log.debug(String.format("SUBJECT = \"%s\"", subject));
subject = subject + " - "+ uuidPart;
// Render
Writer out = new StringWriter();
try {
Map<String, Object> root = new HashMap<>();
root.put("subject", subject);
subjectTemplate.process(root, out);
out.flush();
} catch (Exception ex) {
throw new RuntimeException(
String.format("Problem rendering the email subject")
, ex
);
}
log.debug(String.format("RENERED = \"%s\"", out.toString()));
return out.toString();
}
}