Skip to content

Commit

Permalink
Optionally configure theme to hard-fail w/ runtime exception on missi…
Browse files Browse the repository at this point in the history
…ng template
  • Loading branch information
PandoTom authored and Tom McClure committed Jan 12, 2019
1 parent 527877f commit b9de571
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 25 deletions.
5 changes: 5 additions & 0 deletions ChangeLog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
Release History

v3.5.0 - 2019-01-12 tmcclure

Optionally fire runtime exception on missing template
Prefix boolean bean properties with "is_" only for methods that start with "is"

v3.4.0 - 2018-10-21 tmcclure

New @AccessAsPojo and @AccessAsBean annotations to hint object-mapping logic
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Available from Maven Central:
<dependency>
<groupId>com.x5dev</groupId>
<artifactId>chunk-templates</artifactId>
<version>3.4.0</version>
<version>3.5.0</version>
</dependency>
```

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<groupId>com.x5dev</groupId>
<artifactId>chunk-templates</artifactId>
<packaging>jar</packaging>
<version>3.4.0</version>
<version>3.5.0</version>
<name>Chunk Templates</name>
<description>Chunk Template Engine for Java</description>
<url>http://www.x5software.com/chunk/</url>
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/x5/template/Chunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,15 +243,15 @@
* Updates: <A href="http://www.x5software.com/chunk/">Chunk Documentation</A><BR>
*
* @author Tom McClure
* @version 3.4.0
* @version 3.5.0
*/

public class Chunk implements Map<String,Object>
{
public static final int HASH_THRESH = 8;
public static final int DEPTH_LIMIT = 17;

public static final String VERSION = "3.4.0";
public static final String VERSION = "3.5.0";

public static final String TRUE = "TRUE";

Expand Down
28 changes: 28 additions & 0 deletions src/main/java/com/x5/template/TemplateNotFoundException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.x5.template;

public class TemplateNotFoundException extends RuntimeException
{
private String msg;
private Throwable cause;

public TemplateNotFoundException(String msg)
{
this.msg = msg;
}

public TemplateNotFoundException(String msg, Throwable cause)
{
this.msg = msg;
this.cause = cause;
}

public String getMessage()
{
return msg;
}

public Throwable getRootCause()
{
return cause;
}
}
56 changes: 36 additions & 20 deletions src/main/java/com/x5/template/TemplateSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public class TemplateSet implements ContentSource, ChunkFactory
private Object resourceContext = null;

private boolean prettyFail = true;
private boolean hardFail = false;
private String expectedEncoding = TemplateDoc.getDefaultEncoding();

public TemplateSet() {}
Expand Down Expand Up @@ -265,38 +266,48 @@ private Snippet _get(String name, String extension, boolean prettyFail)
}
}
} catch (java.io.IOException e) {
if (!prettyFail) return null;

StringBuilder errmsg = new StringBuilder("[error fetching ");
StringBuilder errmsg = new StringBuilder("error fetching ");
errmsg.append(extension);
errmsg.append(" template '");
errmsg.append(name);
errmsg.append("']<!-- ");
errmsg.append("'");

if (hardFail) {
throw new TemplateNotFoundException(errmsg.toString(), e);
}

if (!prettyFail) return null;

StringWriter w = new StringWriter();
e.printStackTrace(new PrintWriter(w));
errmsg.append(w.toString());
errmsg.append(" -->");
StringBuilder trace = new StringBuilder();
trace.append("<!-- ");
trace.append(w.toString());
trace.append(" -->");

template = Snippet.getSnippet(errmsg.toString());
template = Snippet.getSnippet("[" + errmsg.toString() + "]" + trace.toString());
}
}

if (template == null) {
if (prettyFail) {
StringBuilder errmsg = new StringBuilder();
errmsg.append(extension);
errmsg.append(" template '");
errmsg.append(name);
errmsg.append("' not found");

if (hardFail) {
throw new TemplateNotFoundException(errmsg.toString() + ". Looked in: " + filename);
}

StringBuilder errmsg = new StringBuilder();
errmsg.append("[");
errmsg.append(extension);
errmsg.append(" template '");
errmsg.append(name);
errmsg.append("' not found]<!-- looked in [");
errmsg.append(filename);
errmsg.append("] -->");
if (!prettyFail) return null;

template = Snippet.getSnippet(errmsg.toString());
} else {
return null;
}
StringBuilder details = new StringBuilder();
details.append("<!-- looked in [");
details.append(filename);
details.append("] -->");

template = Snippet.getSnippet("[" + errmsg.toString() + "]" + details.toString());
}

return template;
Expand Down Expand Up @@ -600,6 +611,11 @@ public void signalFailureWithNull()
this.prettyFail = false;
}

public void setHardFail(boolean hardFail)
{
this.hardFail = hardFail;
}

public String getTemplatePath(String templateName, String ext)
{
String stub = TemplateDoc.truncateNameToStub(templateName);
Expand Down
19 changes: 18 additions & 1 deletion src/main/java/com/x5/template/Theme.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class Theme implements ContentSource, ChunkFactory
private int cacheMins = 0;

private String localeCode = null;
private boolean hardFailMissingTemplate = false;
private boolean renderErrs = true;
private PrintStream errLog = null;

Expand All @@ -38,6 +39,9 @@ public Theme(ThemeConfig config)
if (config.hideErrors()) {
this.setErrorHandling(false, config.getErrorLog());
}
if (config.abortOnMissingTemplate()) {
this.setAbortOnMissingTemplate(true);
}

ChunkFilter[] filters = config.getFilters();
if (filters != null) {
Expand Down Expand Up @@ -140,6 +144,7 @@ private void init()
if (layerNames == null) {
TemplateSet simple = new TemplateSet(classpathThemesFolder, themesFolder, fileExtension, cacheMins);
if (!renderErrs) simple.signalFailureWithNull();
if (hardFailMissingTemplate) simple.setHardFail(true);
themeLayers.add(simple);
} else {
for (int i=0; i<layerNames.length; i++) {
Expand All @@ -150,6 +155,9 @@ private void init()
// layers, a null response is required to search the
// next layer in the stack for the missing template.
x.signalFailureWithNull();
// likewise, failure to locate a template in all layers is handled here, not in the layer TemplateSet.
x.setHardFail(false);

themeLayers.add(x);
}
}
Expand Down Expand Up @@ -276,6 +284,10 @@ private Snippet prettyFail(String templateName, String ext)
Chunk.logChunkError(errLog, err.toString());
}

if (hardFailMissingTemplate) {
throw new TemplateNotFoundException(err.toString());
}

return renderErrs ? Snippet.getSnippet(err.toString()) : null;
}

Expand Down Expand Up @@ -457,4 +469,9 @@ public void setErrorHandling(boolean renderErrs, PrintStream errLog)
this.errLog = errLog;
}

}
public void setAbortOnMissingTemplate(boolean hardFail)
{
this.hardFailMissingTemplate = hardFail;
}

}
11 changes: 11 additions & 0 deletions src/main/java/com/x5/template/ThemeConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class ThemeConfig
public static final String LAYER_NAMES = "layers";
public static final String DEFAULT_EXT = "default_extension";
public static final String CACHE_MINUTES = "cache_minutes";
public static final String THROW_ERRORS = "throw_errors";
public static final String HIDE_ERRORS = "hide_errors";
public static final String ERROR_LOG = "error_log";
public static final String FILTERS = "filters";
Expand All @@ -33,6 +34,7 @@ public class ThemeConfig
private int cacheMinutes = 0;
private String locale = null;
private String encoding = null;
private boolean throwErrors = false;
private boolean hideErrors = false;
private PrintStream errorLog = null;
private ChunkFilter[] filters = null;
Expand Down Expand Up @@ -70,6 +72,10 @@ public void set(String configKey, String value)
} catch (NumberFormatException e) {
System.err.println("Chunk Theme config error: cache_minutes must be a number.");
}
} else if (configKey.equals(THROW_ERRORS)) {
if (value != null && !value.equalsIgnoreCase("FALSE")) {
this.throwErrors = true;
}
} else if (configKey.equals(HIDE_ERRORS)) {
if (value != null && !value.equalsIgnoreCase("FALSE")) {
this.hideErrors = true;
Expand Down Expand Up @@ -203,6 +209,11 @@ public String getEncoding()
return this.encoding;
}

public boolean abortOnMissingTemplate()
{
return this.throwErrors;
}

public boolean hideErrors()
{
return this.hideErrors;
Expand Down
79 changes: 79 additions & 0 deletions src/test/java/com/x5/template/ThemeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,85 @@ public void testAltExtensionLoader()
assertEquals("snippet", snippet.toString());
}

@Test
public void testNotFoundInlineError()
{
Theme theme = new Theme();
theme.setErrorHandling(true, null);
Chunk c = theme.makeChunk("does_not_exist");

assertTrue(c.toString().contains("not found"));
}

@Test
public void testNotFoundSuppressInlineError()
{
Theme theme = new Theme();
theme.setErrorHandling(false, null);
Chunk c = theme.makeChunk("does_not_exist");

assertFalse(c.toString().contains("not found"));
}

@Test(expected = TemplateNotFoundException.class)
public void testNotFoundThrowsException()
{
Theme theme = new Theme();
theme.setAbortOnMissingTemplate(true);
Chunk c = theme.makeChunk("does_not_exist");
c.toString();
}

@Test(expected = TemplateNotFoundException.class)
public void testDeepNotFoundThrowsException()
{
Theme theme = new Theme();
theme.setAbortOnMissingTemplate(true);
Chunk c = theme.makeChunk();
c.append("{.include does_not_exist}");
c.toString();
}

@Test
public void testOverrideLayerWithAbortOnMissing()
{
Theme theme = new Theme("themes","test/base,test/override");
theme.setAbortOnMissingTemplate(true);
Chunk c = theme.makeChunk("chunk_test");

assertEquals("Override Layer", c.toString().trim());
}

@Test(expected = TemplateNotFoundException.class)
public void testOverrideLayerThrowsWithAbortOnMissing()
{
Theme theme = new Theme("themes","test/base,test/override");
theme.setAbortOnMissingTemplate(true);
Chunk c = theme.makeChunk("does_not_exist");
c.toString();
}

@Test
public void testLayersWithAbortOnMissing()
{
Theme theme = new Theme("themes","test/base,test/override");
theme.setAbortOnMissingTemplate(true);
Chunk c = theme.makeChunk("BUG29_MACRO");

assertEquals(38, c.toString().length());
}

@Test
public void testOverrideLayerWithoutAbortOnMissing()
{
Theme theme = new Theme("themes","test/base,test/override");
theme.setErrorHandling(true, null);
theme.setAbortOnMissingTemplate(false);
Chunk c = theme.makeChunk("chunk_not_exists");

assertTrue(c.toString().contains("not found"));
}

public static class DummyLoader extends TemplateProvider
{
public String loadContainerDoc(String docName)
Expand Down

0 comments on commit b9de571

Please sign in to comment.