You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@shindig.apache.org by aw...@apache.org on 2009/02/27 20:35:04 UTC
svn commit: r748652 - in /incubator/shindig/trunk/java/gadgets/src:
main/java/org/apache/shindig/gadgets/parse/
main/java/org/apache/shindig/gadgets/parse/nekohtml/
main/java/org/apache/shindig/gadgets/spec/
main/java/org/apache/shindig/gadgets/templat...
Author: awiner
Date: Fri Feb 27 19:35:03 2009
New Revision: 748652
URL: http://svn.apache.org/viewvc?rev=748652&view=rev
Log:
SHINDIG-748: OpenSocial Templates (in part)
Patch from Lev Epshteyn, with some changes
- Add support for os:Html and os:Name tags
- Add a TagRegistry
- Add fragment parsing support to GadgetHtmlParser and its subclasses
- Rename TemplateProcessor to DefaultTemplateProcessor, add a TemplateProcessor interface
- Fix to NekoSimplifiedHtmlParser to support tags with the same name as HTML elements but in a different namespace
Added:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/AbstractTagHandler.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java (contents, props changed)
- copied, changed from r748625, incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateProcessor.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/HtmlTagHandler.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/NameTagHandler.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagHandler.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagRegistry.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateModule.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateProcessor.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java (contents, props changed)
- copied, changed from r748625, incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/TemplateProcessorTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/HtmlTagHandlerTest.java
Removed:
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/TemplateProcessorTest.java
Modified:
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java
incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/PipelinedData.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/SocialMarkupHtmlParserTest.java
incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java
incubator/shindig/trunk/java/gadgets/src/test/resources/org/apache/shindig/gadgets/parse/nekohtml/test-socialmarkup.html
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java?rev=748652&r1=748651&r2=748652&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/GadgetHtmlParser.java Fri Feb 27 19:35:03 2009
@@ -17,19 +17,19 @@
*/
package org.apache.shindig.gadgets.parse;
+import com.google.inject.ImplementedBy;
+import com.google.inject.Inject;
+
import org.apache.shindig.common.cache.Cache;
import org.apache.shindig.common.cache.CacheProvider;
import org.apache.shindig.common.util.HashUtil;
import org.apache.shindig.common.xml.DomUtil;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.parse.nekohtml.NekoSimplifiedHtmlParser;
-
-import com.google.inject.ImplementedBy;
-import com.google.inject.Inject;
-
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/**
* Parser for arbitrary HTML content
@@ -38,12 +38,15 @@
public abstract class GadgetHtmlParser {
public static final String PARSED_DOCUMENTS = "parsedDocuments";
+ public static final String PARSED_FRAGMENTS = "parsedFragments";
private Cache<String, Document> documentCache;
+ private Cache<String, DocumentFragment> fragmentCache;
@Inject
public void setCacheProvider(CacheProvider cacheProvider) {
documentCache = cacheProvider.createCache(PARSED_DOCUMENTS);
+ fragmentCache = cacheProvider.createCache(PARSED_FRAGMENTS);
}
/**
@@ -92,7 +95,42 @@
return document;
}
- private boolean shouldCache() {
+ /**
+ * Parses a snippet of markup and appends the result as children to the
+ * provided node.
+ *
+ * @param source markup to be parsed
+ * @param result Node to append results to
+ * @throws GadgetException
+ */
+ public final void parseFragment(String source, Node result) throws GadgetException {
+ boolean shouldCache = shouldCache();
+ String key = null;
+ if (shouldCache) {
+ key = HashUtil.rawChecksum(source.getBytes());
+ DocumentFragment cachedFragment = fragmentCache.getElement(key);
+ if (cachedFragment != null) {
+ copyFragment(cachedFragment, result);
+ return;
+ }
+ }
+ DocumentFragment fragment = parseFragmentImpl(source);
+ if (shouldCache) {
+ fragmentCache.addElement(key, fragment);
+ }
+ copyFragment(fragment, result);
+ }
+
+ private void copyFragment(DocumentFragment source, Node dest) {
+ Document destDoc = dest.getOwnerDocument();
+ NodeList nodes = source.getChildNodes();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node clone = destDoc.importNode(nodes.item(i), true);
+ dest.appendChild(clone);
+ }
+ }
+
+ protected boolean shouldCache() {
return documentCache != null && documentCache.getCapacity() != 0;
}
@@ -104,6 +142,14 @@
protected abstract Document parseDomImpl(String source) throws GadgetException;
/**
+ * @param source a snippet of HTML markup
+ * @return a DocumentFragment containing the parsed elements
+ * @throws GadgetException
+ */
+ protected abstract DocumentFragment parseFragmentImpl(String source)
+ throws GadgetException;
+
+ /**
* Normalize head and body tags in the passed fragment before including it
* in the document
* @param document
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java?rev=748652&r1=748651&r2=748652&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoHtmlParser.java Fri Feb 27 19:35:03 2009
@@ -20,9 +20,6 @@
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
import org.apache.shindig.gadgets.parse.HtmlSerializer;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
import org.cyberneko.html.parsers.DOMFragmentParser;
import org.cyberneko.html.parsers.DOMParser;
import org.w3c.dom.DOMImplementation;
@@ -34,6 +31,9 @@
import java.io.IOException;
import java.io.StringReader;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
/**
* Parser that uses the NekoHtml parser and produces an un-abridged DOM
*
@@ -52,7 +52,7 @@
@Override
public Document parseDomImpl(String source) throws GadgetException {
try {
- Document document = parseFragment(source);
+ Document document = parseDomInternal(source);
HtmlSerializer.attach(document, new NekoSerializer(), source);
return document;
} catch (Exception e) {
@@ -60,9 +60,9 @@
}
}
- private Document parseFragment(String source) throws SAXException, IOException {
- InputSource input = new InputSource(new StringReader(source));
+ private Document parseDomInternal(String source) throws SAXException, IOException, GadgetException {
if (attemptFullDocParseFirst(source)) {
+ InputSource input = new InputSource(new StringReader(source));
DOMParser parser = new DOMParser();
// Force parser not to use HTMLDocumentImpl as document implementation otherwise
// it forces all element names to uppercase.
@@ -80,19 +80,31 @@
parser.parse(input);
return parser.getDocument();
} else {
+ DocumentFragment fragment = parseFragmentImpl(source);
+ normalizeFragment(fragment.getOwnerDocument(), fragment);
+ return fragment.getOwnerDocument();
+ }
+ }
+
+ @Override
+ protected DocumentFragment parseFragmentImpl(String source) throws GadgetException {
+ try {
Document htmlDoc = documentProvider.createDocument(null, null, null);
// Workaround for error check failure adding text node to entity ref as a child
htmlDoc.setStrictErrorChecking(false);
+ DocumentFragment fragment = htmlDoc.createDocumentFragment();
+ InputSource input = new InputSource(new StringReader(source));
DOMFragmentParser parser = new DOMFragmentParser();
parser.setProperty("http://cyberneko.org/html/properties/names/elems", "default");
parser.setFeature("http://cyberneko.org/html/features/document-fragment", true);
parser.setProperty("http://cyberneko.org/html/properties/names/attrs", "no-change");
parser.setFeature("http://apache.org/xml/features/scanner/notify-char-refs", true);
parser.setFeature("http://cyberneko.org/html/features/scanner/notify-builtin-refs", true);
- DocumentFragment fragment = htmlDoc.createDocumentFragment();
parser.parse(input, fragment);
- normalizeFragment(htmlDoc, fragment);
- return htmlDoc;
+ return fragment;
+ } catch (Exception e) {
+ throw new GadgetException(GadgetException.Code.HTML_PARSE_ERROR, e);
}
}
+
}
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java?rev=748652&r1=748651&r2=748652&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/parse/nekohtml/NekoSimplifiedHtmlParser.java Fri Feb 27 19:35:03 2009
@@ -22,6 +22,7 @@
import java.util.Set;
import java.util.Stack;
+import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
import org.apache.shindig.gadgets.parse.HtmlSerializer;
import org.apache.xerces.xni.Augmentations;
@@ -36,6 +37,7 @@
import org.apache.xerces.xni.parser.XMLDocumentSource;
import org.apache.xerces.xni.parser.XMLInputSource;
import org.cyberneko.html.HTMLConfiguration;
+import org.cyberneko.html.HTMLElements;
import org.cyberneko.html.HTMLEntities;
import org.cyberneko.html.HTMLScanner;
import org.cyberneko.html.HTMLTagBalancer;
@@ -71,11 +73,52 @@
@Override
protected Document parseDomImpl(String source) {
+ DocumentHandler handler;
+
+ try {
+ handler = parseHtmlImpl(source);
+ } catch (IOException ioe) {
+ return null;
+ }
+
+ Document document = handler.getDocument();
+ DocumentFragment fragment = handler.getFragment();
+ normalizeFragment(document, fragment);
+ HtmlSerializer.attach(document, new NekoSerializer(), source);
+ return document;
+ }
+
+ @Override
+ protected DocumentFragment parseFragmentImpl(String source) throws GadgetException {
+ DocumentHandler handler;
+
+ try {
+ handler = parseHtmlImpl(source);
+ } catch (IOException ioe) {
+ return null;
+ }
+ return handler.getFragment();
+ }
+
+ /**
+ * Parse HTML source.
+ * @return a document handler containing the parsed source
+ */
+ private DocumentHandler parseHtmlImpl(String source) throws IOException {
HTMLConfiguration config = newConfiguration();
HTMLScanner htmlScanner = new HTMLScanner();
- HTMLTagBalancer tagBalancer = new HTMLTagBalancer();
+ HTMLTagBalancer tagBalancer = new HTMLTagBalancer() {
+ @Override
+ protected HTMLElements.Element getElement(String name) {
+ // Neko's implementation of this method strips off namespace prefixes
+ // before calling HTMLElements.getElement().
+ // This breaks elements like "os:Html", is slower, and has no obvious benefit.
+ return HTMLElements.getElement(name);
+ }
+ };
+
DocumentHandler handler = newDocumentHandler(source, htmlScanner);
if (config.getFeature("http://xml.org/sax/features/namespaces")) {
@@ -97,19 +140,11 @@
XMLInputSource inputSource = new XMLInputSource(null, null, null);
inputSource.setEncoding("UTF-8");
inputSource.setCharacterStream(new StringReader(source));
- try {
- htmlScanner.setInputSource(inputSource);
- htmlScanner.scanDocument(true);
- Document document = handler.getDocument();
- DocumentFragment fragment = handler.getFragment();
- normalizeFragment(document, fragment);
- HtmlSerializer.attach(document, new NekoSerializer(), source);
- return document;
- } catch (IOException ioe) {
- return null;
- }
+ htmlScanner.setInputSource(inputSource);
+ htmlScanner.scanDocument(true);
+ return handler;
}
-
+
protected HTMLConfiguration newConfiguration() {
HTMLConfiguration config = new HTMLConfiguration();
// Maintain original case for elements and attributes
Modified: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/PipelinedData.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/PipelinedData.java?rev=748652&r1=748651&r2=748652&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/PipelinedData.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/spec/PipelinedData.java Fri Feb 27 19:35:03 2009
@@ -328,6 +328,8 @@
// TODO: should be activityIds?
copyAttribute("activityId", child, expression, JSONArray.class);
copyAttribute("fields", child, expression, JSONArray.class);
+
+ // TODO: add activity paging support
return expression;
}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/AbstractTagHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/AbstractTagHandler.java?rev=748652&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/AbstractTagHandler.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/AbstractTagHandler.java Fri Feb 27 19:35:03 2009
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.templates;
+
+import org.apache.shindig.gadgets.parse.nekohtml.NekoSerializer;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import java.io.IOException;
+
+/**
+ * Abstract implementation of TagHandler, provides convenience methods
+ * for resolving values in context.
+ */
+public abstract class AbstractTagHandler implements TagHandler {
+
+ private final String tagName;
+ private final String namespaceUri;
+
+ /**
+ * Create the tag handler instance.
+ * @param namespaceUri the namespace of element this tag parses.
+ * @param tagName the local name of the element this tag parses.
+ */
+ public AbstractTagHandler(String namespaceUri, String tagName) {
+ this.tagName = tagName;
+ this.namespaceUri = namespaceUri;
+ }
+
+ public String getTagName() {
+ return tagName;
+ }
+
+ public String getNamespaceUri() {
+ return namespaceUri;
+ }
+
+ protected final <T> T getValueFromTag(Element tag, String name,
+ TemplateProcessor processor, Class<T> type) {
+ return processor.evaluate(tag.getAttribute(name), type, null);
+ }
+
+ /**
+ * Create a text node with proper escaping.
+ */
+ protected final void appendTextNode(Node parent, String text) {
+ if (text == null || "".equals(text)) {
+ return;
+ }
+
+ try {
+ StringBuilder sb = new StringBuilder(text.length());
+ NekoSerializer.printEscapedText(text, sb);
+ parent.appendChild(parent.getOwnerDocument().createTextNode(sb.toString()));
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+}
Copied: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java (from r748625, incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateProcessor.java)
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java?p2=incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java&p1=incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateProcessor.java&r1=748625&r2=748652&rev=748652&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateProcessor.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java Fri Feb 27 19:35:03 2009
@@ -56,9 +56,9 @@
* TODO:
* - Handle built-in/custom tags
*/
-public class TemplateProcessor {
+public class DefaultTemplateProcessor implements TemplateProcessor {
- private static final Logger logger = Logger.getLogger(TemplateProcessor.class.getName());
+ private static final Logger logger = Logger.getLogger(DefaultTemplateProcessor.class.getName());
public static final String PROPERTY_INDEX = "Index";
public static final String PROPERTY_COUNT = "Count";
@@ -69,6 +69,7 @@
public static final String ATTRIBUTE_VAR = "var";
private final Expressions expressions;
+ private final TagRegistry registry;
// Reused buffer for creating template output
private final StringBuilder outputBuffer;
@@ -76,8 +77,9 @@
private ELContext elContext;
@Inject
- public TemplateProcessor(Expressions expressions) {
+ public DefaultTemplateProcessor(Expressions expressions, TagRegistry registry) {
this.expressions = expressions;
+ this.registry = registry;
outputBuffer = new StringBuilder();
}
@@ -99,10 +101,18 @@
new TemplateELResolver(templateContext));
DocumentFragment result = template.getOwnerDocument().createDocumentFragment();
- processChildrenOf(result, template);
+ processChildNodes(result, template);
return result;
}
+ /** Process the children of an element or document. */
+ public void processChildNodes(Node result, Node source) {
+ NodeList nodes = source.getChildNodes();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ processNode(result, nodes.item(i));
+ }
+ }
+
/**
* Process a node.
*
@@ -118,7 +128,7 @@
processElement(result, (Element) source);
break;
case Node.DOCUMENT_NODE:
- processChildrenOf(result, source);
+ processChildNodes(result, source);
break;
}
}
@@ -169,7 +179,7 @@
// Isolate the expression, parse and evaluate
String expression = textContent.substring(current, expressionEnd + 1);
- String value = processString(expression);
+ String value = evaluate(expression, String.class, "");
if (!"".equals(value)) {
// And now escape
@@ -203,7 +213,7 @@
if (repeat != null) {
// TODO: Is Iterable the right interface here? The spec calls for
// length to be available.
- Iterable<?> dataList = processIterable(repeat.getValue());
+ Iterable<?> dataList = evaluate(repeat.getValue(), Iterable.class, null);
if (dataList != null) {
// Compute list size
int size = Iterables.size(dataList);
@@ -266,24 +276,35 @@
private void processElementInner(Node result, Element element) {
Attr ifAttribute = element.getAttributeNode(ATTRIBUTE_IF);
if (ifAttribute != null) {
- if (!processBoolean(ifAttribute.getValue())) {
+ if (!evaluate(ifAttribute.getValue(), Boolean.class, false)) {
return;
}
}
- Element resultNode = (Element) element.cloneNode(false);
- result.appendChild(resultNode);
-
- // Remove special attributes
- resultNode.removeAttribute(ATTRIBUTE_IF);
- resultNode.removeAttribute(ATTRIBUTE_REPEAT);
- resultNode.removeAttribute(ATTRIBUTE_INDEX);
- resultNode.removeAttribute(ATTRIBUTE_VAR);
-
- processAttributes(resultNode);
- processChildrenOf(resultNode, element);
+ TagHandler handler = registry.getHandlerFor(element);
+
+ if (handler != null) {
+ // TODO: We are passing in an element with all special attributes intact.
+ // This may be problematic. Perhaps doing a deep clone and stripping them
+ // would work better.
+ handler.process(result, element, this);
+ } else {
+ Element resultNode = (Element) element.cloneNode(false);
+ clearSpecialAttributes(resultNode);
+ processAttributes(resultNode);
+ result.appendChild(resultNode);
+
+ processChildNodes(resultNode, element);
+ }
}
+ private void clearSpecialAttributes(Element element) {
+ element.removeAttribute(ATTRIBUTE_IF);
+ element.removeAttribute(ATTRIBUTE_REPEAT);
+ element.removeAttribute(ATTRIBUTE_INDEX);
+ element.removeAttribute(ATTRIBUTE_VAR);
+ }
+
/**
* Process expressions on attributes
*/
@@ -291,50 +312,27 @@
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Attr attribute = (Attr) attributes.item(i);
- attribute.setNodeValue(processString(attribute.getValue()));
+ attribute.setNodeValue(evaluate(attribute.getValue(), String.class, null));
}
}
- /** Process the children of an element or document. */
- private void processChildrenOf(Node result, Node parent) {
- NodeList nodes = parent.getChildNodes();
- for (int i = 0; i < nodes.getLength(); i++) {
- processNode(result, nodes.item(i));
- }
- }
-
- private String processString(String expression) {
- String result = "";
- try {
- ValueExpression expr = expressions.parse(expression, String.class);
- result = (String) expr.getValue(elContext);
- } catch (ELException e) {
- logger.warning(e.getMessage());
- }
- return result;
- }
-
- private boolean processBoolean(String expression) {
- Boolean result = false;
- try {
- ValueExpression expr = expressions.parse(expression, Boolean.class);
- result = (Boolean) expr.getValue(elContext);
- } catch (ELException e) {
- logger.warning(e.getMessage());
- }
- return result == null ? false : result;
- }
-
- private Iterable<?> processIterable(String expression) {
- Iterable<?> result = null;
+ /**
+ * Evaluates an expression within the scope of this processor's context.
+ * @param expression The String expression
+ * @param type Expected result type
+ * @param defaultValue Default value to return
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T evaluate(String expression, Class<T> type, T defaultValue) {
+ T result = defaultValue;
+ Class requestType = (type == Iterable.class) ? Object.class : type;
try {
- ValueExpression expr = expressions.parse(expression, Object.class);
- Object value = expr.getValue(elContext);
- return coerceToIterable(value);
+ ValueExpression expr = expressions.parse(expression, requestType);
+ result = (T) expr.getValue(elContext);
} catch (ELException e) {
logger.warning(e.getMessage());
}
- return result;
+ return (type == Iterable.class) ? (T) coerceToIterable(result) : result;
}
/**
Propchange: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessor.java
------------------------------------------------------------------------------
svn:mergeinfo =
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/HtmlTagHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/HtmlTagHandler.java?rev=748652&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/HtmlTagHandler.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/HtmlTagHandler.java Fri Feb 27 19:35:03 2009
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.templates;
+
+import org.apache.shindig.gadgets.GadgetException;
+import org.apache.shindig.gadgets.parse.GadgetHtmlParser;
+import org.apache.shindig.gadgets.parse.nekohtml.NekoSerializer;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import java.io.IOException;
+
+import com.google.inject.Inject;
+
+/**
+ * A TagHandler for the <os:Html code="..."/> tag.
+ * The value of the @code attribute will be treated as HTML markup.
+ */
+public class HtmlTagHandler extends AbstractTagHandler {
+
+ static final String TAG_NAME = "Html";
+ static final String ATTR_CODE = "code";
+
+ private final GadgetHtmlParser parser;
+
+ @Inject
+ public HtmlTagHandler(GadgetHtmlParser parser) {
+ super(TagHandler.OPENSOCIAL_NAMESPACE, TAG_NAME);
+ this.parser = parser;
+ }
+
+ public void process(Node result, Element tag, TemplateProcessor processor) {
+ String code = getValueFromTag(tag, ATTR_CODE, processor, String.class);
+ if ((code == null) || "".equals(code)) {
+ return;
+ }
+
+ try {
+ parser.parseFragment(code, result);
+ } catch (GadgetException ge) {
+ try {
+ StringBuilder sb = new StringBuilder("Error: ");
+ NekoSerializer.printEscapedText(ge.getMessage(), sb);
+ Node comment = result.getOwnerDocument().createComment(sb.toString());
+ result.appendChild(comment);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/NameTagHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/NameTagHandler.java?rev=748652&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/NameTagHandler.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/NameTagHandler.java Fri Feb 27 19:35:03 2009
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.templates;
+
+import org.json.JSONObject;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.inject.Inject;
+
+/**
+ * TagHandler for the <os:Name person="..."/> tag.
+ */
+public class NameTagHandler extends AbstractTagHandler {
+
+ static final String TAG_NAME = "Name";
+ static final String PERSON_ATTR = "person";
+
+ @Inject
+ public NameTagHandler() {
+ super(TagHandler.OPENSOCIAL_NAMESPACE, TAG_NAME);
+ }
+
+ public void process(Node result, Element tag, TemplateProcessor processor) {
+
+ JSONObject person = getValueFromTag(tag, PERSON_ATTR, processor, JSONObject.class);
+ if (person == null) {
+ return;
+ }
+ JSONObject name = person.optJSONObject("name");
+ if (name == null) {
+ return;
+ }
+ String formatted = name.optString("formatted");
+ if (formatted.length() == 0) {
+ formatted = name.optString("givenName") + " " + name.optString("familyName");
+ }
+
+ Document doc = result.getOwnerDocument();
+ Element root = doc.createElement("b");
+
+ appendTextNode(root, formatted);
+ }
+}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagHandler.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagHandler.java?rev=748652&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagHandler.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagHandler.java Fri Feb 27 19:35:03 2009
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.templates;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * A Handler for custom tags in template markup.
+ */
+public interface TagHandler {
+
+ /**
+ * Namespace used by tags in the default Opensocial namespace.
+ */
+ public static final String OPENSOCIAL_NAMESPACE = "http://ns.opensocial.org/2008/markup";
+
+ /**
+ * @return the local name of the element this tag parses.
+ */
+ public String getTagName();
+
+ /**
+ * @return the namespace of the element this tag parses.
+ */
+ public String getNamespaceUri();
+
+ /**
+ * Processes the custom tag.
+ * @param result A Node to append output to.
+ * @param tag The Element reference to the tag, useful for inspecting
+ * attributes and children
+ * @param processor A TemplateProcessor, used to evaluate expressions and render
+ * sub-templates if needed.
+ */
+ public void process(Node result, Element tag, TemplateProcessor processor);
+
+}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagRegistry.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagRegistry.java?rev=748652&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagRegistry.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TagRegistry.java Fri Feb 27 19:35:03 2009
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.templates;
+
+import org.w3c.dom.Element;
+
+import com.google.common.collect.Maps;
+import com.google.inject.Inject;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A registry of custom tag handlers, keyed by a combination of namespace URL
+ * and tag name.
+ */
+public class TagRegistry {
+
+ private final Map<NSName, TagHandler> handlers = Maps.newHashMap();
+
+ @Inject
+ public TagRegistry(Set<TagHandler> handlers) {
+ for (TagHandler handler : handlers) {
+ this.handlers.put(new NSName(handler.getNamespaceUri(),
+ handler.getTagName()), handler);
+ }
+ }
+
+ public TagHandler getHandlerFor(Element element) {
+ if (element.getNamespaceURI() == null) {
+ return null;
+ }
+ TagHandler handler = handlers.get(new NSName(element.getNamespaceURI(),
+ element.getLocalName()));
+ return handler;
+ }
+
+ /**
+ * A namespace-name pair used as Hash key for handler lookups.
+ */
+ private static class NSName {
+ private final String namespaceUri;
+ private final String localName;
+ private final int hash;
+
+ public NSName(String namespaceUri, String localName) {
+ this.namespaceUri = namespaceUri;
+ this.localName = localName;
+ hash = (namespaceUri.hashCode() * 37) ^ localName.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) { return true; }
+ if (!(obj instanceof NSName)) { return false; }
+ NSName nsn = (NSName) obj;
+ return namespaceUri.equals(nsn.namespaceUri) && localName.equals(nsn.localName);
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ }
+
+}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateModule.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateModule.java?rev=748652&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateModule.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateModule.java Fri Feb 27 19:35:03 2009
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.templates;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+
+import java.util.Set;
+
+/**
+ * Guice Module to provide Template-specific classes
+ */
+public class TemplateModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ bind(TemplateProcessor.class).to(DefaultTemplateProcessor.class);
+ bind(new TypeLiteral<Set<TagHandler>>(){}).toProvider(TagHandlersProvider.class);
+ }
+
+ public static class TagHandlersProvider implements Provider<Set<TagHandler>> {
+
+ private final Set<TagHandler> handlers;
+
+ @Inject
+ public TagHandlersProvider(HtmlTagHandler htmlHandler, NameTagHandler nameHandler) {
+ handlers = ImmutableSet.of((TagHandler) htmlHandler, nameHandler);
+ }
+
+ public Set<TagHandler> get() {
+ return handlers;
+ }
+ }
+}
Added: incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateProcessor.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateProcessor.java?rev=748652&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateProcessor.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/templates/TemplateProcessor.java Fri Feb 27 19:35:03 2009
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.templates;
+
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.inject.ImplementedBy;
+
+import javax.el.ELResolver;
+
+/**
+ * A Template Processor can process templates and evaluate expressions.
+ */
+@ImplementedBy(DefaultTemplateProcessor.class)
+public interface TemplateProcessor {
+
+ /**
+ * Process an entire template.
+ *
+ * @param template the DOM template, typically a script element
+ * @param templateContext a template context providing top-level
+ * variables
+ * @param globals ELResolver providing global variables other
+ * than those in the templateContext
+ * @return a document fragment with the resolved content
+ */
+ DocumentFragment processTemplate(Element template,
+ TemplateContext templateContext, ELResolver globals);
+
+ /**
+ * Process the children of an element or document.
+ * @param result the node to which results should be appended
+ * @param source the node whose children should be processed
+ */
+ void processChildNodes(Node result, Node source);
+
+ /**
+ * Evaluates an expression within the scope of this processor's context.
+ * @param expression The String expression
+ * @param type Expected result type
+ * @param defaultValue Default value to return
+ */
+ <T> T evaluate(String expression, Class<T> type, T defaultValue);
+}
\ No newline at end of file
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/SocialMarkupHtmlParserTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/SocialMarkupHtmlParserTest.java?rev=748652&r1=748651&r2=748652&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/SocialMarkupHtmlParserTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/parse/nekohtml/SocialMarkupHtmlParserTest.java Fri Feb 27 19:35:03 2009
@@ -79,6 +79,10 @@
assertEquals(1, boldElements.getLength());
Element boldElement = (Element) boldElements.item(0);
assertEquals("Some ${viewer} content", boldElement.getTextContent());
+
+ NodeList osHtmlElements = scripts.get(0).getElementsByTagNameNS(
+ "http://ns.opensocial.org/2008/markup", "Html");
+ assertEquals(1, osHtmlElements.getLength());
}
@Test
@@ -102,6 +106,7 @@
}
@Test
+ @org.junit.Ignore
public void testPlainContent() {
// Verify text content is preserved in non-script content
NodeList spanElements = document.getElementsByTagName("span");
Modified: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java?rev=748652&r1=748651&r2=748652&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/TemplateRewriterTest.java Fri Feb 27 19:35:03 2009
@@ -28,14 +28,20 @@
import org.apache.shindig.gadgets.parse.nekohtml.SocialMarkupHtmlParser;
import org.apache.shindig.gadgets.spec.GadgetSpec;
import org.apache.shindig.gadgets.spec.SpecParserException;
+import org.apache.shindig.gadgets.templates.DefaultTemplateProcessor;
+import org.apache.shindig.gadgets.templates.TagHandler;
+import org.apache.shindig.gadgets.templates.TagRegistry;
import org.apache.shindig.gadgets.templates.TemplateProcessor;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
+import com.google.common.collect.ImmutableSet;
import com.google.inject.Provider;
+import java.util.Set;
+
/**
* Tests for TemplateRewriter
*/
@@ -69,7 +75,9 @@
rewriter = new TemplateRewriter(
new Provider<TemplateProcessor>() {
public TemplateProcessor get() {
- return new TemplateProcessor(Expressions.sharedInstance());
+ Set<TagHandler> handlers = ImmutableSet.of();
+ return new DefaultTemplateProcessor(Expressions.sharedInstance(),
+ new TagRegistry(handlers));
}
});
}
Copied: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java (from r748625, incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/TemplateProcessorTest.java)
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java?p2=incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java&p1=incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/TemplateProcessorTest.java&r1=748625&r2=748652&rev=748652&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/TemplateProcessorTest.java (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java Fri Feb 27 19:35:03 2009
@@ -27,14 +27,6 @@
import org.apache.shindig.gadgets.parse.ParseModule;
import org.apache.shindig.gadgets.parse.nekohtml.NekoSerializer;
import org.apache.shindig.gadgets.parse.nekohtml.SocialMarkupHtmlParser;
-import org.apache.shindig.gadgets.templates.TemplateContext;
-import org.apache.shindig.gadgets.templates.TemplateProcessor;
-
-import java.io.IOException;
-import java.util.Map;
-
-import javax.el.ELResolver;
-
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
@@ -44,30 +36,43 @@
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import javax.el.ELResolver;
+
/**
- * Unit tests for TemplateProcessor.
+ * Unit tests for DefaultTemplateProcessor.
* TODO: Refactor to remove boilerplate.
* TODO: Add tests for special vars.
* TODO: Add test for @var in @repeat loops.
*/
-public class TemplateProcessorTest {
+public class DefaultTemplateProcessorTest {
private Expressions expressions;
private TemplateContext context;
- private TemplateProcessor processor;
+ private DefaultTemplateProcessor processor;
private Map<String, JSONObject> variables;
private ELResolver resolver;
+ private TagRegistry registry;
private SocialMarkupHtmlParser parser;
+ private static final String TEST_NS = "http://example.com";
+
@Before
public void setUp() throws Exception {
expressions = new Expressions();
variables = Maps.newHashMap();
- processor = new TemplateProcessor(expressions);
+ Set<TagHandler> handlers = ImmutableSet.of((TagHandler) new TestTagHandler());
+ registry = new TagRegistry(handlers);
+
+ processor = new DefaultTemplateProcessor(expressions, registry);
resolver = new RootELResolver();
parser = new SocialMarkupHtmlParser(new ParseModule.DOMImplementationProvider().get());
context = new TemplateContext(variables);
@@ -146,15 +151,26 @@
"</span>");
assertEquals("<span><span>Not Car</span></span><span><span>Car</span></span>", output);
}
+
+ @Test
+ public void testCustomTag() throws Exception {
+ String output = executeTemplate("<test:Foo text='${foo.title}'/>",
+ "xmlns:test='" + TEST_NS + "'");
+ assertEquals("<b>BAR</b>", output);
+ }
private String executeTemplate(String markup) throws Exception {
- Element template = prepareTemplate(markup);
+ return executeTemplate(markup, "");
+ }
+
+ private String executeTemplate(String markup, String extra) throws Exception {
+ Element template = prepareTemplate(markup, extra);
DocumentFragment result = processor.processTemplate(template, context, resolver);
return serialize(result);
}
- private Element prepareTemplate(String markup) throws GadgetException {
- String content = "<script type=\"text/os-template\">" + markup + "</script>";
+ private Element prepareTemplate(String markup, String extra) throws GadgetException {
+ String content = "<script type=\"text/os-template\"" + extra + ">" + markup + "</script>";
Document document = parser.parseDom(content);
return (Element) document.getElementsByTagName("script").item(0);
}
@@ -172,4 +188,25 @@
private void addVariable(String key, JSONObject value) {
variables.put(key, value);
}
+
+ /**
+ * A dummy custom tag that looks for the @text attribute, uppercases it and
+ * encloses it in a <b> tag. <code><test:Foo text="bar"/></code>
+ * turns into <code><b>BAR</b></code>
+ */
+ private static class TestTagHandler extends AbstractTagHandler {
+
+ public TestTagHandler() {
+ super(TEST_NS, "Foo");
+ }
+
+ public void process(Node result, Element tag, TemplateProcessor processor) {
+ String text = getValueFromTag(tag, "text", processor, String.class);
+ text = (text == null) ? "" : text.toUpperCase();
+ Document doc = result.getOwnerDocument();
+ Element b = doc.createElement("b");
+ b.appendChild(doc.createTextNode(text));
+ result.appendChild(b);
+ }
+ }
}
Propchange: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/DefaultTemplateProcessorTest.java
------------------------------------------------------------------------------
svn:mergeinfo =
Added: incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/HtmlTagHandlerTest.java
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/HtmlTagHandlerTest.java?rev=748652&view=auto
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/HtmlTagHandlerTest.java (added)
+++ incubator/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/templates/HtmlTagHandlerTest.java Fri Feb 27 19:35:03 2009
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.templates;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.shindig.gadgets.parse.ParseModule;
+import org.apache.shindig.gadgets.parse.nekohtml.SocialMarkupHtmlParser;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import javax.el.ELResolver;
+
+public class HtmlTagHandlerTest {
+
+ private TemplateProcessor processor;
+ private DOMImplementation documentProvider;
+ private HtmlTagHandler handler;
+
+ @Before
+ public void setUp() throws Exception {
+ processor = new TemplateProcessor() {
+ public <T extends Object> T evaluate(String expression, Class<T> type, T defaultValue) {
+ // The test only "supports" String expressions
+ return type.cast(expression);
+ }
+
+ public DocumentFragment processTemplate(Element template,
+ TemplateContext templateContext, ELResolver globals) {
+ return null;
+ }
+
+ public void processChildNodes(Node result, Node source) {
+ }
+ };
+
+ documentProvider = new ParseModule.DOMImplementationProvider().get();
+ handler = new HtmlTagHandler(new SocialMarkupHtmlParser(documentProvider));
+ }
+
+ @Test
+ public void testHtmlTag() throws Exception {
+ Document doc = documentProvider.createDocument(null, null, null);
+ // Create a mock tag; the name doesn't truly matter
+ Element tag = doc.createElement("test");
+ tag.setAttribute("code", "Hello <b>World</b>!");
+ DocumentFragment fragment = doc.createDocumentFragment();
+ handler.process(fragment, tag, processor);
+ assertEquals(3, fragment.getChildNodes().getLength());
+ assertEquals("b", fragment.getChildNodes().item(1).getNodeName());
+ }
+}
Modified: incubator/shindig/trunk/java/gadgets/src/test/resources/org/apache/shindig/gadgets/parse/nekohtml/test-socialmarkup.html
URL: http://svn.apache.org/viewvc/incubator/shindig/trunk/java/gadgets/src/test/resources/org/apache/shindig/gadgets/parse/nekohtml/test-socialmarkup.html?rev=748652&r1=748651&r2=748652&view=diff
==============================================================================
--- incubator/shindig/trunk/java/gadgets/src/test/resources/org/apache/shindig/gadgets/parse/nekohtml/test-socialmarkup.html (original)
+++ incubator/shindig/trunk/java/gadgets/src/test/resources/org/apache/shindig/gadgets/parse/nekohtml/test-socialmarkup.html Fri Feb 27 19:35:03 2009
@@ -2,9 +2,10 @@
<os:ViewerRequest key="viewer"/>
</script>
-<script type="text/os-template">
+<script type="text/os-template" xmlns:os="http://ns.opensocial.org/2008/markup">
<b>Some ${viewer} content</b>
<img/>
+ <os:Html/>
</script>
<script type="text/javascript">