package org.springframework.samples.tiles;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.tiles.Attribute;
import org.apache.tiles.AttributeContext;
import org.apache.tiles.context.TilesRequestContext;
import org.apache.tiles.preparer.PreparerException;
import org.apache.tiles.preparer.ViewPreparer;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
/**
* Controller for the news tile that retrieves a feed
* mentioned in the definitions file.
*
* @author Alef Arendsen
* @author Juergen Hoeller
*/
public class NewsFeedController implements ViewPreparer {
private NewsFeedConfigurer configurer;
public void setConfigurer(NewsFeedConfigurer configurer) {
this.configurer = configurer;
}
public void execute(TilesRequestContext tilesRequestContext, AttributeContext attributeContext) throws PreparerException {
String uri = this.configurer.feedUri((String) attributeContext.getAttribute("sourceName").getValue());
try {
NewsReader reader = new NewsReader(uri);
int size = Integer.parseInt((String) attributeContext.getAttribute("size").getValue());
List items = new ArrayList();
for (int i = 0; i < size && i < reader.size(); i++) {
NewsItem item = new NewsItem();
item.setLink(reader.getLinkAt(i));
item.setTitle(reader.getTitleAt(i));
item.setSourceName((String) attributeContext.getAttribute("sourceName").getValue());
items.add(item);
}
attributeContext.putAttribute("items", new Attribute(items));
}
catch (Exception ex) {
throw new PreparerException(ex);
}
}
private static class NewsReader {
private Document feed;
private String type;
public NewsReader(String uriString) throws MalformedURLException, DocumentException {
// get and parse the feed
DocumentFactory docFactory = DocumentFactory.getInstance();
SAXReader saxReader = new SAXReader(docFactory, false);
URL uri = new URL(uriString);
this.feed = saxReader.read(uri);
// determine the type
this.type = feed.getRootElement().getName();
}
private String getChannelPrefix() {
if ("rss".equals(this.type)) {
return "/*/*/";
}
else {
return "/*/";
}
}
public int size() {
// todo: RDF somehow doesn't work with XPATH expression, fix it
if ("RDF".equals(this.type)) {
int size = 0;
Iterator it = feed.getRootElement().elements().iterator();
while (it.hasNext()) {
String qName = ((Element) it.next()).getQualifiedName();
if (qName.equals("item")) {
size++;
}
}
return size;
}
return this.feed.selectNodes(getChannelPrefix() + "item").size();
}
public String getItemAsXML(int index) {
Node node = null;
// determine RDF or other format
if ("RDF".equals(this.type)) {
node = getRDFNodeAt(index, null);
}
else {
node = this.feed.selectSingleNode(getChannelPrefix() + "item[" + (index + 1) + "]");
}
// return as XML
if (node != null) {
return node.asXML();
}
return null;
}
public String getChannelTitle() {
return this.feed.getRootElement().element("channel").element("title").getText();
}
public String getChannelLink() {
return this.feed.getRootElement().element("channel").element("link").getText();
}
public String getLinkAt(int i) {
return getItemNodeValue(i, "link");
}
public String getTitleAt(int i) {
return getItemNodeValue(i, "title");
}
public String getDescriptionAt(int i) {
return getItemNodeValue(i, "description");
}
private String getItemNodeValue(int index, String nodeName) {
String value = null;
// determine RDF or other format
if ("RDF".equals(this.type)) {
value = getRDFNodeAt(index, nodeName).getText();
}
else {
value = this.feed.selectSingleNode(
getChannelPrefix() + "item[" + (index + 1) + "]/" + nodeName).getText();
}
return value;
}
private List getRDFItemNodes() {
// iterate through the entire document in search for item nodes
List items = new ArrayList(this.feed.getRootElement().elements().size());
Iterator it = this.feed.getRootElement().elements().iterator();
while (it.hasNext()) {
Element elem = (Element) it.next();
String qName = elem.getQualifiedName();
if ("item".equals(qName)) {
// found one, increment size
items.add(elem);
}
}
return items;
}
private Node getRDFNodeAt(int i, String subNode) {
// get all the item nodes
List items = getRDFItemNodes();
// find the correct item, and either return a 'subNode' or itself
Element item = (Element) items.get(i);
if (subNode == null) {
return item;
}
else {
return item.element(subNode);
}
}
}
}