core/com.nokia.carbide.discovery.ui/src/com/nokia/carbide/internal/discovery/ui/editor/SimpleRSSReader.java
/*
* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.carbide.internal.discovery.ui.editor;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.nokia.carbide.discovery.ui.Activator;
import com.nokia.carbide.discovery.ui.Messages;
/**
* A simple RSS reader
* @see http://www.rssboard.org/rss-specification
*/
public class SimpleRSSReader {
public static class Rss {
private List<Channel> channels = new ArrayList<Channel>();
public List<Channel> getChannels() {
return channels;
}
protected void addChannel(Channel channel) {
channels.add(channel);
}
}
public static class Container {
private String title;
private URL link;
private String description;
private Date pubDate;
private List<String> categories = new ArrayList<String>();
public String getTitle() {
return title;
}
public URL getLink() {
return link;
}
public String getDescription() {
return description;
}
public Date getPubDate() {
return pubDate;
}
public String[] getCategories() {
return (String[]) categories.toArray(new String[categories.size()]);
}
public boolean isValid() {
return title != null && link != null && description != null;
}
protected void setField(String element, String value) {
if (RSSHandler.TITLE.equalsIgnoreCase(element))
title = value;
else if (RSSHandler.LINK.equalsIgnoreCase(element)) {
try {
link = new URL(value);
} catch (MalformedURLException e) {
// don't store malformed URLs
Activator.logError(Messages.SimpleRSSReader_BadURLError, e);
}
}
else if (RSSHandler.DESCRIPTION.equalsIgnoreCase(element) || RSSHandler.SUMMARY.equalsIgnoreCase(element))
description = value;
else if (RSSHandler.PUBDATE.equalsIgnoreCase(element)) {
pubDate = parseRFC822Date(value);
}
else if (RSSHandler.CATEGORY.equalsIgnoreCase(element))
categories.add(value);
}
private Date parseRFC822Date(String value) {
SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z"); //$NON-NLS-1$
try {
return format.parse(value);
} catch (ParseException e) {
}
return null;
}
}
public static class Channel extends Container {
List<Item> items = new ArrayList<Item>();
public List<Item> getItems() {
return items;
}
protected void addItem(Item item) {
items.add(item);
}
public boolean hasItems() {
return !items.isEmpty();
}
}
public static class Item extends Container {
private Channel channel;
public Item(Channel channel) {
this.channel = channel;
}
public Channel getChannel() {
return channel;
}
}
private static class RSSHandler extends DefaultHandler {
private static final String CHANNEL = "channel"; //$NON-NLS-1$
private static final String TITLE = "title"; //$NON-NLS-1$
private static final String LINK = "link"; //$NON-NLS-1$
private static final String DESCRIPTION = "description"; //$NON-NLS-1$
private static final String SUMMARY = "atom:summary"; //$NON-NLS-1$
private static final String ITEM = "item"; //$NON-NLS-1$
private static final String PUBDATE = "pubDate"; //$NON-NLS-1$
private static final String CATEGORY = "category"; //$NON-NLS-1$
private static final Set<String> charsElements = new HashSet<String>();
static {
charsElements.add(TITLE.toLowerCase());
charsElements.add(LINK.toLowerCase());
charsElements.add(DESCRIPTION.toLowerCase());
charsElements.add(SUMMARY.toLowerCase());
charsElements.add(PUBDATE.toLowerCase());
charsElements.add(CATEGORY.toLowerCase());
}
private Channel curChannel;
private Item curItem;
private StringBuffer charsBuf;
private Rss rss;
public RSSHandler(Rss rss) {
this.rss = rss;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (charsElements.contains(qName.toLowerCase())) {
charsBuf = new StringBuffer();
}
if (CHANNEL.equalsIgnoreCase(qName)) {
curChannel = new Channel();
}
else if (ITEM.equalsIgnoreCase(qName) && curChannel != null) {
curItem = new Item(curChannel);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (CHANNEL.equalsIgnoreCase(qName)) {
if (curChannel != null && curChannel.isValid() && curChannel.hasItems())
rss.addChannel(curChannel);
curChannel = null;
curItem = null;
}
else if (ITEM.equalsIgnoreCase(qName)) {
if (curChannel != null && curItem != null && curItem.isValid())
curChannel.addItem(curItem);
curItem = null;
}
else if (charsBuf != null && curChannel != null) {
if (curItem != null)
curItem.setField(qName, charsBuf.toString().trim());
else
curChannel.setField(qName, charsBuf.toString().trim());
charsBuf = null;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (charsBuf != null) {
charsBuf.append(new String(ch, start, length));
}
}
}
public static Rss readRSS(URL url) throws SAXException, IOException, ParserConfigurationException {
Rss rss = new Rss();
URLConnection connection = url.openConnection();
connection.connect();
InputStream inputStream = url.openStream();
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(inputStream, new RSSHandler(rss));
return rss;
}
}