Unexplainable resources.getResourceAsString() behavior

Hello Everyone

I have a situation that I cannot explain or correct and need some assistance.

Operating System: macOS Catalina 10.15.7
Browser: Safari Version 14.0.1 (15610.2.11.51.10, 15610)
File System: Case-Sensitive Journaled HFS+ (APFS)
Datebase: MySQL 8.0.19

CUBA Platform version: 7.2.10
CUBA Studio plugin version: 14.3-193
IntelliJ version: CUBA Studio 2019.3

Use Case: I am displaying a preview of the user’s input text, after it’s been processed with a FreeMarker template, in a textArea before I send it as an email so that the user can examine the complete message.

Problem: When I use the email sending method described in the developer’s guide, the user’s text is correctly processed with my FreeMarker template and the mail is sent as expected. My FreeMarker template is located at this path:

/modules/core/src/com/company/nfm/templates/initialContact.en.txt

and my source code (without all of the variables) is as follows and does work correctly:

String templatePath = “com/company/nfm/templates/initialContact.en.txt";
EmailInfo emailInfo = EmailInfoBuilder.create()
.setAddresses(toAddress)
.setCaption(subject)
.setFrom(null)
.setBcc(bccAddress)
.setSendInOneMessage(true)
.setBodyContentType(EmailInfo.TEXT_CONTENT_TYPE)
.setTemplatePath(templatePath)
.setTemplateParameters(Collections.singletonMap(“contact”, contact))
.build();
emailService.sendEmailAsync(emailInfo);

However, when I use the following code to explicitly process the text with my FreeMarker template for previewing, the “template” string returned by resources.getResourceAsString(templatePath) is always null …
private void previewMessage() {
String previewStr;
String templatePath = “com/company/nfm/templates/initialContact.en.txt”;
String template = resources.getResourceAsString(templatePath);
if (template == null) {
previewStr = messages.getMessage(“com.company.nfm.web.screens.contact”, “contactTemplatePathError”) + " " + templatePath;
contactPreviewTextArea.setValue(previewStr);
return;
}
previewStr = TemplateHelper.processTemplate(template, Collections.singletonMap(“contact”, contact));
contactPreviewTextArea.setValue(previewStr);
}

…unless I copy my template to the following path:

/deploy/app_home/app/conf/com/company/nfm/templates/initialContact.en.txt

If I copy my template to the deployment path my preview text is generated as expected.

I do not understand why emailService.sendEmailAsync(emailInfo) finds my template at the “/modules/core/src/com/company/nfm/templates/initialContact.en.txt” but my preview function does not and requires that I copy the template to the deployment path.

The source code of processBodyTemplate(), directly below, uses the exact same method that my preview does and it works correctly, otherwise my email would not be formatted correctly. Therefore, I cannot understand where the path reference is being manipulated, so that the deployment path is needed for my preview.

Can someone please tell me what I am missing or doing wrong?

Many thanks in advance.

Happy Holidays & Best regards
Chris

Hi,

I suspect that you send emails using a service, thus the template file is located in the core module. Since the web module has no dependency on the core mode, the template file isn’t available.

When you put the template file in /deploy/app_home/app/conf/… directory (instead of app-core) the file becomes available for the web client.

I’d recommend putting the template file to the global module because both core and web depend on it, so it will be available to both modules.

Regards,
Gleb

Hi Gleb

Thank you very much for the quick response and the good observation.

In the meantime I have tried both the global and web modules without success. resources.getResourceAsString(templatePath) only works from the web client via the deploy path.

This behavior is correctly described in the Resources documentation and that is why I could not understand why it was working for the /modules/core path when using the emailService.sendEmailAsync(emailInfo) call.

I was expecting the sendEmailAsync call to use the same configuration folder since it is also using resources.getResourceAsString(). And I was therefore looking for a “development” flag or something similar in the configuration that would allow sendEmailAsync to locate the resources within the /modules/core path. It might be worth noting this difference in the documentation for those people using the FreeMarker templates for other purposes.

I can live with the current situation and will find a way to copy my templates into the deployment path during development. I have never modified the deployment setup before but I will study it in more detail and find a way. Thanks again and…

Best regards
Chris

Alternatively, you can use the ResourceService bean to fetch a resource from the core layer.

Hi Gleb

The ResourceService solved it…

I replaced
String template = resources.getResourceAsString(templatePath);
with
String template = resourceService.getResourceAsString(templatePath);
and it works now as expected.

It’s so obvious that it’s embarrassing but that’s what happens when starting off with the wrong assumption; it led me too far down the wrong path and into too many details. Anyway, I learned something again about the framework and how to approach my problem solving. Great!

Many thanks again!

Best regards
Chris