Add an eventCartridge (handler) for methods that throw; add template identifier (a name) to input

This commit is contained in:
2023-05-30 14:04:15 -05:00
parent 794fb5e87a
commit c78d598035
3 changed files with 108 additions and 8 deletions

View File

@ -26,20 +26,30 @@ import java.io.StringWriter;
import java.util.Map;
import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
import com.kingsrook.qqq.backend.core.model.templates.RenderTemplateInput;
import com.kingsrook.qqq.backend.core.model.templates.RenderTemplateOutput;
import com.kingsrook.qqq.backend.core.model.templates.TemplateType;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.event.EventCartridge;
import org.apache.velocity.app.event.MethodExceptionEventHandler;
import org.apache.velocity.context.Context;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
** Basic action to render a template!
**
** hard-coded built to only assume Velocity right now. could expand (and refactor) in future.
*******************************************************************************/
public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplateInput, RenderTemplateOutput>
{
private static final QLogger LOG = QLogger.getLogger(RenderTemplateAction.class);
/*******************************************************************************
**
@ -53,8 +63,11 @@ public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplate
{
Velocity.init();
Context context = new VelocityContext(input.getContext());
setupEventHandlers(context);
StringWriter stringWriter = new StringWriter();
Velocity.evaluate(context, stringWriter, "logTag", input.getCode());
Velocity.evaluate(context, stringWriter, StringUtils.hasContent(input.getTemplateIdentifier()) ? input.getTemplateIdentifier() : "anonymous", input.getCode());
output.setResult(stringWriter.getBuffer().toString());
}
else
@ -67,12 +80,28 @@ public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplate
/*******************************************************************************
**
*******************************************************************************/
private static void setupEventHandlers(Context context)
{
EventCartridge eventCartridge = new EventCartridge();
eventCartridge.addEventHandler((MethodExceptionEventHandler) (ctx, aClass, method, exception, info) ->
{
LOG.info("Exception in velocity template", exception, logPair("at", info.toString()));
return (null);
});
eventCartridge.attachToContext(context);
}
/*******************************************************************************
** Most convenient static wrapper to render a Velocity template.
*******************************************************************************/
public static String renderVelocity(AbstractActionInput parentActionInput, Map<String, Object> context, String code) throws QException
{
return (render(parentActionInput, TemplateType.VELOCITY, context, code));
return (render(TemplateType.VELOCITY, context, code));
}
@ -80,7 +109,7 @@ public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplate
/*******************************************************************************
** Convenient static wrapper to render a template of an arbitrary type (language).
*******************************************************************************/
public static String render(AbstractActionInput parentActionInput, TemplateType templateType, Map<String, Object> context, String code) throws QException
public static String render(TemplateType templateType, Map<String, Object> context, String code) throws QException
{
RenderTemplateInput renderTemplateInput = new RenderTemplateInput();
renderTemplateInput.setCode(code);

View File

@ -31,6 +31,7 @@ import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
*******************************************************************************/
public class RenderTemplateInput extends AbstractActionInput
{
private String templateIdentifier;
private String code; // todo - TemplateReference, like CodeReference??
private TemplateType templateType;
@ -147,4 +148,35 @@ public class RenderTemplateInput extends AbstractActionInput
return (this);
}
/*******************************************************************************
** Getter for templateIdentifier
*******************************************************************************/
public String getTemplateIdentifier()
{
return (this.templateIdentifier);
}
/*******************************************************************************
** Setter for templateIdentifier
*******************************************************************************/
public void setTemplateIdentifier(String templateIdentifier)
{
this.templateIdentifier = templateIdentifier;
}
/*******************************************************************************
** Fluent setter for templateIdentifier
*******************************************************************************/
public RenderTemplateInput withTemplateIdentifier(String templateIdentifier)
{
this.templateIdentifier = templateIdentifier;
return (this);
}
}

View File

@ -29,6 +29,7 @@ import com.kingsrook.qqq.backend.core.model.templates.RenderTemplateInput;
import com.kingsrook.qqq.backend.core.model.templates.RenderTemplateOutput;
import com.kingsrook.qqq.backend.core.model.templates.TemplateType;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -36,8 +37,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
** Unit test for RenderTemplateAction
*******************************************************************************/
class RenderTemplateActionTest extends BaseTest
public class RenderTemplateActionTest extends BaseTest
{
private int doThrowCallCount = 0;
/*******************************************************************************
**
@ -82,11 +86,46 @@ class RenderTemplateActionTest extends BaseTest
@Test
void testMissingType()
{
RenderTemplateInput parentActionInput = new RenderTemplateInput();
assertThatThrownBy(() -> RenderTemplateAction.render(parentActionInput, null, Map.of("name", "Darin"), "Hello, $name"))
assertThatThrownBy(() -> RenderTemplateAction.render(null, Map.of("name", "Darin"), "Hello, $name"))
.isInstanceOf(QException.class)
.hasMessageContaining("Unsupported Template Type");
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testExceptionInVelocity() throws QException
{
RenderTemplateInput renderTemplateInput = new RenderTemplateInput();
renderTemplateInput.setCode("""
This should throw: $this.doThrow().
This should throw silently: $!this.doThrow().
""");
renderTemplateInput.setContext(Map.of("this", this));
renderTemplateInput.setTemplateType(TemplateType.VELOCITY);
RenderTemplateOutput output = new RenderTemplateAction().execute(renderTemplateInput);
assertThat(output.getResult())
.contains("throw: $this.doThrow().")
.contains("throw silently: .");
///////////////////////////////////////////////////////
// make sure our method got called twice as expected //
///////////////////////////////////////////////////////
assertEquals(2, doThrowCallCount);
}
/*******************************************************************************
**
*******************************************************************************/
public String doThrow() throws Exception
{
doThrowCallCount++;
throw (new Exception("You asked to throw..."));
}
}