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 java.util.Map;
import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction; import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction;
import com.kingsrook.qqq.backend.core.exceptions.QException; 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.actions.AbstractActionInput;
import com.kingsrook.qqq.backend.core.model.templates.RenderTemplateInput; 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.RenderTemplateOutput;
import com.kingsrook.qqq.backend.core.model.templates.TemplateType; 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.VelocityContext;
import org.apache.velocity.app.Velocity; 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 org.apache.velocity.context.Context;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/******************************************************************************* /*******************************************************************************
** Basic action to render a template! ** 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> public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplateInput, RenderTemplateOutput>
{ {
private static final QLogger LOG = QLogger.getLogger(RenderTemplateAction.class);
/******************************************************************************* /*******************************************************************************
** **
@ -52,9 +62,12 @@ public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplate
if(TemplateType.VELOCITY.equals(input.getTemplateType())) if(TemplateType.VELOCITY.equals(input.getTemplateType()))
{ {
Velocity.init(); Velocity.init();
Context context = new VelocityContext(input.getContext()); Context context = new VelocityContext(input.getContext());
setupEventHandlers(context);
StringWriter stringWriter = new StringWriter(); 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()); output.setResult(stringWriter.getBuffer().toString());
} }
else 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. ** Most convenient static wrapper to render a Velocity template.
*******************************************************************************/ *******************************************************************************/
public static String renderVelocity(AbstractActionInput parentActionInput, Map<String, Object> context, String code) throws QException 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). ** 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 renderTemplateInput = new RenderTemplateInput();
renderTemplateInput.setCode(code); renderTemplateInput.setCode(code);

View File

@ -31,6 +31,7 @@ import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
*******************************************************************************/ *******************************************************************************/
public class RenderTemplateInput extends AbstractActionInput public class RenderTemplateInput extends AbstractActionInput
{ {
private String templateIdentifier;
private String code; // todo - TemplateReference, like CodeReference?? private String code; // todo - TemplateReference, like CodeReference??
private TemplateType templateType; private TemplateType templateType;
@ -147,4 +148,35 @@ public class RenderTemplateInput extends AbstractActionInput
return (this); 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.RenderTemplateOutput;
import com.kingsrook.qqq.backend.core.model.templates.TemplateType; import com.kingsrook.qqq.backend.core.model.templates.TemplateType;
import org.junit.jupiter.api.Test; 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.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -36,8 +37,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
/******************************************************************************* /*******************************************************************************
** Unit test for RenderTemplateAction ** 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 @Test
void testMissingType() void testMissingType()
{ {
RenderTemplateInput parentActionInput = new RenderTemplateInput(); assertThatThrownBy(() -> RenderTemplateAction.render(null, Map.of("name", "Darin"), "Hello, $name"))
assertThatThrownBy(() -> RenderTemplateAction.render(parentActionInput, null, Map.of("name", "Darin"), "Hello, $name"))
.isInstanceOf(QException.class) .isInstanceOf(QException.class)
.hasMessageContaining("Unsupported Template Type"); .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..."));
}
} }