diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/templates/RenderTemplateAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/templates/RenderTemplateAction.java index 5449c942..1bb6e3ce 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/templates/RenderTemplateAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/templates/RenderTemplateAction.java @@ -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 { + private static final QLogger LOG = QLogger.getLogger(RenderTemplateAction.class); + + /******************************************************************************* ** @@ -52,9 +62,12 @@ public class RenderTemplateAction extends AbstractQActionFunction + { + 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 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 context, String code) throws QException + public static String render(TemplateType templateType, Map context, String code) throws QException { RenderTemplateInput renderTemplateInput = new RenderTemplateInput(); renderTemplateInput.setCode(code); diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/templates/RenderTemplateInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/templates/RenderTemplateInput.java index eeaf05aa..87302d40 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/templates/RenderTemplateInput.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/templates/RenderTemplateInput.java @@ -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); + } + } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/templates/RenderTemplateActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/templates/RenderTemplateActionTest.java index 1b8a8676..926b80f5 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/templates/RenderTemplateActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/templates/RenderTemplateActionTest.java @@ -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...")); + } + } \ No newline at end of file