diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/Attributes.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/Attributes.java index 2cf2f659f..22f1ad17b 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/Attributes.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/Attributes.java @@ -30,6 +30,8 @@ import java.util.LinkedHashMap; */ public class Attributes extends LinkedHashMap { + private static final long serialVersionUID = 4103241472140545630L; + public Attributes add(String key, String value) { return add(key, value, true); } diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/DefaultTheme.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/DefaultTheme.java index 98ba4c79a..62f5da639 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/DefaultTheme.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/DefaultTheme.java @@ -38,7 +38,7 @@ public class DefaultTheme implements Theme { private static final Logger LOG = LoggerFactory.getLogger(DefaultTheme.class); private String name; - private Map> handlerFactories; + protected Map> handlerFactories; protected void setName(String name) { this.name = name; @@ -48,6 +48,47 @@ public class DefaultTheme implements Theme { this.handlerFactories = handlers; } + + /** + * Set (replace if exists) the tag handler factories for specific tag + * + * @param tagName + * @param handlers + */ + protected void setTagHandlerFactories(String tagName, List handlers) { + if (tagName != null && handlers != null && this.handlerFactories != null) { + handlerFactories.put(tagName, handlers); + } + } + + /** + * Insert a new tag handler into a sequence of tag handlers for a specific tag + * TODO: Need to take care of serializers, if handler specified is not a TagSerializer it should never + * be placed after the serializer, but if it is not a TagSerializer, it should never + * + * @param tagName + * @param sequence + * @param factory + */ + protected void insertTagHandlerFactory(String tagName, int sequence, TagHandlerFactory factory) { + + if (tagName != null && factory != null && this.handlerFactories != null) { + + List tagHandlerFactories = handlerFactories.get(tagName); + + if (tagHandlerFactories == null) { + tagHandlerFactories = new ArrayList(); //TODO: Could use public FactoryList here + } + + if (sequence > tagHandlerFactories.size()) { + sequence = tagHandlerFactories.size(); + } + + //TODO, need to account for TagHandlers vs. TagSerializers here + tagHandlerFactories.add(sequence, factory); + } + } + public String getName() { return name; } @@ -70,7 +111,7 @@ public class DefaultTheme implements Theme { handlers.add(0, prev); } - TagSerializer ser = (TagSerializer) handlers.get(handlers.size() - 1); + // TagSerializer ser = (TagSerializer) handlers.get(handlers.size() - 1); TagGenerator gen = (TagGenerator) handlers.get(0); try { diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/JavaTemplateEngine.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/JavaTemplateEngine.java index 6cbdf0014..1294ab1b3 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/JavaTemplateEngine.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/JavaTemplateEngine.java @@ -27,12 +27,20 @@ import org.apache.struts2.components.template.TemplateRenderingContext; import org.apache.struts2.views.java.simple.SimpleTheme; import java.util.HashMap; +import java.util.StringTokenizer; + +import com.opensymphony.xwork2.util.logging.LoggerFactory; +import com.opensymphony.xwork2.util.logging.Logger; +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import com.opensymphony.xwork2.inject.Inject; /** * Template engine that renders tags using java implementations */ public class JavaTemplateEngine extends BaseTemplateEngine { + private static final Logger LOG = LoggerFactory.getLogger(JavaTemplateEngine.class); + private Themes themes = new Themes() {{ add(new SimpleTheme()); }}; @@ -64,4 +72,34 @@ public class JavaTemplateEngine extends BaseTemplateEngine { } } + /** + * Allows for providing custom theme classes (implementations of the org.apache.struts2.views.java.Theme) interface + * for custom rendering of tags using the javatemplates engine + * + * @param themeClasses a comma delimited list of custom theme class names + */ + @Inject("struts.javatemplates.customThemes") + public void setThemeClasses(String themeClasses) { + + StringTokenizer customThemes = new StringTokenizer(themeClasses, ","); + + while (customThemes.hasMoreTokens()) { + String themeClass = customThemes.nextToken().trim(); + try { + LOG.info("Registering custom theme '" + themeClass + "' to javatemplates engine"); + + + //FIXME: This means Themes must have no-arg constructor - should use object factory here + //ObjectFactory.getObjectFactory().buildBean(ClassLoaderUtil.loadClass(themeClass, getClass()), null); + themes.add((Theme) ClassLoaderUtil.loadClass(themeClass, getClass()).newInstance()); + + } catch (ClassCastException cce) { + LOG.error("Invalid java them class '" + themeClass + "'. Class does not implement 'org.apache.struts2.views.java.Theme' interface"); + } catch (ClassNotFoundException cnf) { + LOG.error("Invalid java theme class '" + themeClass + "'. Class not found"); + } catch (Exception e) { + LOG.error("Could not find messages file " + themeClass + ".properties. Skipping"); + } + } + } } diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/XHTMLTagSerializer.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/XHTMLTagSerializer.java index cd41d53ad..a938c2ea3 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/XHTMLTagSerializer.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/XHTMLTagSerializer.java @@ -32,7 +32,7 @@ import java.io.Writer; */ public class XHTMLTagSerializer implements TagSerializer { - private Writer writer; + protected Writer writer; public void characters(String text) throws IOException { characters(text, true); diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/DivHandler.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/DivHandler.java index a586c81ec..0b0b27b24 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/DivHandler.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/DivHandler.java @@ -35,7 +35,7 @@ public class DivHandler extends AbstractTagHandler implements TagGenerator { .addIfExists("class", params.get("cssClass")) .addIfExists("style", params.get("cssStyle")) .addIfExists("title", params.get("title")); - start("div", attrs); + super.start("div", attrs); } public static class CloseHandler extends AbstractTagHandler implements TagGenerator { diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/HeadHandler.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/HeadHandler.java index fcd0fccf3..58b0cb167 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/HeadHandler.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/HeadHandler.java @@ -37,9 +37,13 @@ public class HeadHandler extends AbstractTagHandler implements TagGenerator { attrs.put("type", "text/javascript"); String base = ServletActionContext.getRequest().getContextPath(); + attrs.put("base", base); + StringBuilder sb = new StringBuilder(); - if (base != null) + if (base != null) { sb.append(base); + } + sb.append("/struts/utils.js"); attrs.put("src", sb.toString()); diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SelectHandler.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SelectHandler.java index 03a8bf98b..a355ce370 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SelectHandler.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SelectHandler.java @@ -76,10 +76,10 @@ public class SelectHandler extends AbstractTagHandler implements TagGenerator { //key Object itemKey = findValue(listKey != null ? listKey : "top"); - String itemKeyStr = StringUtils.defaultString(itemKey.toString()); + String itemKeyStr = StringUtils.defaultString(itemKey == null ? null : itemKey.toString()); //value Object itemValue = findValue(listValue != null ? listValue : "top"); - String itemValueStr = StringUtils.defaultString(itemValue.toString()); + String itemValueStr = StringUtils.defaultString(itemValue == null ? null : itemValue.toString()); boolean selected = ContainUtil.contains(value, itemKey); writeOption(itemKeyStr, itemValueStr, selected); diff --git a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SimpleTheme.java b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SimpleTheme.java index 015b577d0..e667ef5ce 100644 --- a/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SimpleTheme.java +++ b/plugins/javatemplates/src/main/java/org/apache/struts2/views/java/simple/SimpleTheme.java @@ -32,36 +32,41 @@ import java.util.List; public class SimpleTheme extends DefaultTheme { public SimpleTheme() { - setHandlerFactories(new HashMap>() {{ - put("text", new FactoryList(TextFieldHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("textfield", new FactoryList(TextFieldHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("select", new FactoryList(SelectHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("form", new FactoryList(FormHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("form-close", new FactoryList(FormHandler.CloseHandler.class)); - put("a", new FactoryList(AnchorHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("a-close", new FactoryList(AnchorHandler.CloseHandler.class)); - put("checkbox", new FactoryList(CheckboxHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("file", new FactoryList(FileHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("password", new FactoryList(PasswordHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("label", new FactoryList(LabelHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("reset", new FactoryList(ResetHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("submit", new FactoryList(SubmitHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("submit-close", new FactoryList(SubmitHandler.CloseHandler.class)); - put("textarea", new FactoryList(TextAreaHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("actionerror", new FactoryList(ActionErrorHandler.class)); - put("token", new FactoryList(TokenHandler.class)); - put("actionmessage", new FactoryList(ActionMessageHandler.class)); - put("head", new FactoryList(HeadHandler.class)); - put("hidden", new FactoryList(HiddenHandler.class)); - put("fielderror", new FactoryList(FieldErrorHandler.class)); - put("div", new FactoryList(DivHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); - put("div-close", new FactoryList(DivHandler.CloseHandler.class)); - put("empty", new FactoryList(EmptyHandler.class)); - }}); + setHandlerFactories(new HashMap>() { + { + put("text", new FactoryList(TextFieldHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("textfield", new FactoryList(TextFieldHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("select", new FactoryList(SelectHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("form", new FactoryList(FormHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("form-close", new FactoryList(FormHandler.CloseHandler.class)); + put("a", new FactoryList(AnchorHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("a-close", new FactoryList(AnchorHandler.CloseHandler.class)); + put("checkbox", new FactoryList(CheckboxHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("file", new FactoryList(FileHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("password", new FactoryList(PasswordHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("label", new FactoryList(LabelHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("reset", new FactoryList(ResetHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("submit", new FactoryList(SubmitHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("submit-close", new FactoryList(SubmitHandler.CloseHandler.class)); + put("textarea", new FactoryList(TextAreaHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("actionerror", new FactoryList(ActionErrorHandler.class)); + put("token", new FactoryList(TokenHandler.class)); + put("actionmessage", new FactoryList(ActionMessageHandler.class)); + put("head", new FactoryList(HeadHandler.class)); + put("hidden", new FactoryList(HiddenHandler.class)); + put("fielderror", new FactoryList(FieldErrorHandler.class)); + put("div", new FactoryList(DivHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class)); + put("div-close", new FactoryList(DivHandler.CloseHandler.class)); + put("empty", new FactoryList(EmptyHandler.class)); + } + }); setName("simple"); } private class FactoryList extends ArrayList { + + private static final long serialVersionUID = -1551895041394434032L; + public FactoryList(Class... classes) { super(); for (Class cls : classes) { diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java index a7057f36b..8297db587 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java @@ -31,7 +31,7 @@ public class HeadTest extends AbstractTest { map.putAll(tag.getParameters()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); - String expected = s(""); + String expected = s(""); assertEquals(expected, output); }