WW-3009 Extensibility Improvements to javatemplates plugin - patch (project scope)

submitted by Eric Chijioke

git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@767518 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Rainer Hermanns
2009-04-22 13:37:01 +00:00
parent b84fc5b6bc
commit efd35b5e9a
9 changed files with 124 additions and 34 deletions
@@ -30,6 +30,8 @@ import java.util.LinkedHashMap;
*/
public class Attributes extends LinkedHashMap<String, String> {
private static final long serialVersionUID = 4103241472140545630L;
public Attributes add(String key, String value) {
return add(key, value, true);
}
@@ -38,7 +38,7 @@ public class DefaultTheme implements Theme {
private static final Logger LOG = LoggerFactory.getLogger(DefaultTheme.class);
private String name;
private Map<String, List<TagHandlerFactory>> handlerFactories;
protected Map<String, List<TagHandlerFactory>> 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<TagHandlerFactory> 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<TagHandlerFactory> tagHandlerFactories = handlerFactories.get(tagName);
if (tagHandlerFactories == null) {
tagHandlerFactories = new ArrayList<TagHandlerFactory>(); //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 {
@@ -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");
}
}
}
}
@@ -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);
@@ -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 {
@@ -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());
@@ -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);
@@ -32,36 +32,41 @@ import java.util.List;
public class SimpleTheme extends DefaultTheme {
public SimpleTheme() {
setHandlerFactories(new HashMap<String, List<TagHandlerFactory>>() {{
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<String, List<TagHandlerFactory>>() {
{
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<TagHandlerFactory> {
private static final long serialVersionUID = -1551895041394434032L;
public FactoryList(Class... classes) {
super();
for (Class cls : classes) {
@@ -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("<script type='text/javascript' src='/some/path/struts/utils.js'></script>");
String expected = s("<script type='text/javascript' base='/some/path' src='/some/path/struts/utils.js'></script>");
assertEquals(expected, output);
}