bg.fourweb.android.rss.RssHandler.java Source code

Java tutorial

Introduction

Here is the source code for bg.fourweb.android.rss.RssHandler.java

Source

/*
 * This file is part of AndroidRssParser.
 * 
 * AndroidRssParser is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * 
 * AndroidRssParser is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with Foobar.  If not, see
 * <http://www.gnu.org/licenses/>.
 */
package bg.fourweb.android.rss;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import android.webkit.MimeTypeMap;

public class RssHandler extends AbsRssHandler {

    private static class Thumbnail implements Comparable<Thumbnail> {

        private int width, height;
        private String url;
        private String mimeType;

        public Thumbnail(String url, String mimeType, int width, int height) {
            super();
            this.url = url != null ? url : StringUtils.EMPTY;
            this.mimeType = mimeType != null ? mimeType : StringUtils.EMPTY;
            this.width = Math.max(0, width);
            this.height = Math.max(0, height);
        }

        @Override
        public int compareTo(Thumbnail another) {
            return (width + height) - (another.width + another.height);
        }

    }

    // channel elements
    // @formatter:off
    private static final int ELT_INVALID = 0;
    private static final int ELT_RSS = 1;
    private static final int ELT_CHANNEL = 2;
    private static final int ELT_TITLE = 4;
    private static final int ELT_LINK = 5;
    private static final int ELT_DESCRIPTION = 6;
    private static final int ELT_LANGUAGE = 7;
    private static final int ELT_COPYRIGHT = 8;
    private static final int ELT_MANAGINGEDITOR = 9;
    private static final int ELT_WEBMASTER = 10;
    private static final int ELT_PUBDATE = 11;
    private static final int ELT_LASTBUILDDATE = 12;
    private static final int ELT_CATEGORY = 13;
    private static final int ELT_GENERATOR = 14;
    private static final int ELT_DOCS = 15;
    private static final int ELT_CLOUD = 16;
    private static final int ELT_TTL = 17;
    private static final int ELT_IMAGE = 18;
    private static final int ELT_IMAGE_URL = 34;
    private static final int ELT_IMAGE_WIDTH = 37;
    private static final int ELT_IMAGE_HEIGHT = 38;
    private static final int ELT_RATING = 19;
    private static final int ELT_TEXTINPUT = 20;
    private static final int ELT_SKIPHOURS = 21;
    private static final int ELT_SKIPDAYS = 22;
    private static final int ELT_ITEM = 23;
    private static final int ELT_AUTHOR = 27;
    private static final int ELT_COMMENTS = 29;
    private static final int ELT_ENCLOSURE = 30;
    private static final int ELT_GUID = 31;
    private static final int ELT_SOURCE = 33;

    // y: this isn't part of the RSS standard, but too many **** include it in feeds
    private static final int ELT_THUMBNAIL = 40;
    // @formatter:on

    private static final Map<String, Integer> elements = new HashMap<String, Integer>();

    static {
        // @formatter:off
        elements.put("rss", ELT_RSS);
        elements.put("channel", ELT_CHANNEL);
        elements.put("title", ELT_TITLE);
        elements.put("link", ELT_LINK);
        elements.put("description", ELT_DESCRIPTION);
        elements.put("language", ELT_LANGUAGE);
        elements.put("copyright", ELT_COPYRIGHT);
        elements.put("managingEditor", ELT_MANAGINGEDITOR);
        elements.put("webMaster", ELT_WEBMASTER);
        elements.put("pubDate", ELT_PUBDATE);
        elements.put("lastBuildDate", ELT_LASTBUILDDATE);
        elements.put("category", ELT_CATEGORY);
        elements.put("generator", ELT_GENERATOR);
        elements.put("docs", ELT_DOCS);
        elements.put("cloud", ELT_CLOUD);
        elements.put("ttl", ELT_TTL);
        elements.put("image", ELT_IMAGE);
        elements.put("url", ELT_IMAGE_URL);
        elements.put("width", ELT_IMAGE_WIDTH);
        elements.put("height", ELT_IMAGE_HEIGHT);
        elements.put("rating", ELT_RATING);
        elements.put("textInput", ELT_TEXTINPUT);
        elements.put("skipHours", ELT_SKIPHOURS);
        elements.put("skipDays", ELT_SKIPDAYS);
        elements.put("item", ELT_ITEM);
        elements.put("author", ELT_AUTHOR);
        elements.put("comments", ELT_COMMENTS);
        elements.put("enclosure", ELT_ENCLOSURE);
        elements.put("guid", ELT_GUID);
        elements.put("source", ELT_SOURCE);

        elements.put("thumbnail", ELT_THUMBNAIL);
        // @formatter:on
    }

    protected ItemBuilder currentItemB;
    private FeedBuilder feedB = new FeedBuilder();
    private StringBuilder valueB;
    // private boolean inChannel = false;
    private boolean inItems = false;
    private boolean inImage = false;
    private String categoryDomain;
    private int currentElt;
    private Thumbnail largestThumbnail;

    public RssHandler(ParserOptions opts) {
        super(opts);
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes)
            throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        checkStopCondition();

        boolean createValueB = false;

        currentElt = elements.containsKey(localName) ? elements.get(localName) : ELT_INVALID;
        // @formatter:off
        switch (currentElt) {
        // case ELT_CHANNEL: inChannel = true; break;
        case ELT_ITEM:
            inItems = true;
            currentItemB = new ItemBuilder();
            break;
        case ELT_IMAGE:
            inImage = true;
            break; // channel
        // ---
        // tags that contain value only
        case ELT_TITLE: // channel & image & item
        case ELT_LINK: // channel & image & item
        case ELT_DESCRIPTION: // channel & item
        case ELT_LANGUAGE: // channel
        case ELT_COPYRIGHT: // channel
        case ELT_MANAGINGEDITOR: // channel
        case ELT_WEBMASTER: // channel
        case ELT_PUBDATE: // channel & item
        case ELT_LASTBUILDDATE: // channel
        case ELT_GENERATOR: // channel
        case ELT_DOCS: // channel
        case ELT_CLOUD: // channel
        case ELT_TTL: // channel
        case ELT_IMAGE_URL: // image
        case ELT_IMAGE_WIDTH: // image
        case ELT_IMAGE_HEIGHT: // image
        case ELT_RATING: // channel
        case ELT_SKIPHOURS: // channel
        case ELT_SKIPDAYS: // channel
        case ELT_AUTHOR: // item
        case ELT_COMMENTS: // item
            createValueB = true;
            break;
        // ---
        // tags that contain both values and attributes
        case ELT_CATEGORY:
            categoryDomain = attributes.getValue("domain");
            createValueB = true;
            break; // channel & item
        case ELT_GUID:
            currentItemB.guidIsPermaLink(attributes.getValue("isPermaLink"));
            createValueB = true;
            break; // item
        case ELT_SOURCE:
            currentItemB.sourceUrl(attributes.getValue("url"));
            createValueB = true;
            break; // item    
        // ---
        // tags that contain attributes only
        case ELT_ENCLOSURE: {// item
            final String url = attributes.getValue("url");
            int length;
            try {
                length = Integer.parseInt(attributes.getValue("length"));
            } catch (NumberFormatException e) {
                length = 0;
            }
            final String mimeType = attributes.getValue("type");
            currentItemB.addEnclosureUrl(url, length, mimeType);
            break;
        }
        case ELT_THUMBNAIL: {
            final String url = attributes.getValue("url");
            final String mimeType = StringUtils.isEmpty(url) ? ""
                    : MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url));
            int width;
            try {
                width = Integer.parseInt(attributes.getValue("width"));
            } catch (NumberFormatException e) {
                width = 0;
            }
            int height;
            try {
                height = Integer.parseInt(attributes.getValue("height"));
            } catch (NumberFormatException e) {
                height = 0;
            }
            final Thumbnail t = new Thumbnail(url, mimeType, width, height);
            if (largestThumbnail == null || largestThumbnail.compareTo(t) < 0) {
                largestThumbnail = t;
            }
        }
        }

        // @formatter:on
        if (createValueB) {
            valueB = new StringBuilder(63);
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        checkStopCondition();
        switch (currentElt) {
        case ELT_CHANNEL:
            /* inChannel = */
            inItems = false;
            break;
        case ELT_ITEM:
            inItems = true;
            break;
        case ELT_TITLE: // channel & image & item
        case ELT_LINK: // channel & image & item
        case ELT_DESCRIPTION: // channel & item
        case ELT_LANGUAGE: // channel
        case ELT_COPYRIGHT: // channel
        case ELT_MANAGINGEDITOR: // channel
        case ELT_WEBMASTER: // channel
        case ELT_PUBDATE: // channel & item
        case ELT_LASTBUILDDATE: // channel
        case ELT_CATEGORY: // channel & item
        case ELT_GENERATOR: // channel
        case ELT_DOCS: // channel
        case ELT_CLOUD: // channel
        case ELT_TTL: // channel
        case ELT_IMAGE: // channel
        case ELT_IMAGE_URL: // image
        case ELT_IMAGE_WIDTH: // image
        case ELT_IMAGE_HEIGHT: // image
        case ELT_RATING: { // channel
        }
        // TODO: add <hour> and <day?> tags
        // case ELT_SKIPHOURS: // channel
        // case ELT_SKIPDAYS: // channel
        case ELT_AUTHOR: // item
        case ELT_COMMENTS: // item
            // case ELT_ENCLOSURE: // item
        case ELT_GUID: // item
        case ELT_SOURCE: // item
            valueB.append(new String(ch, start, length));
        }
    }

    @Override
    @SuppressWarnings("unused")
    public void endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        checkStopCondition();
        final Integer endElt = elements.get(localName);
        if (endElt == null) {
            return;
        }
        // @formatter:off
        switch (endElt) {
        case ELT_CHANNEL:
            /* inChannel = */ inItems = false;
            return;
        case ELT_ITEM:
            if (currentItemB.getFirstEnclosure() == null && largestThumbnail != null) {
                currentItemB.addEnclosureUrl(largestThumbnail.url, 0, largestThumbnail.mimeType);
            }
            largestThumbnail = null;
            feedB.addItem(currentItemB.build());
            return;
        }
        if (valueB == null) {
            return;
        }
        String value = valueB.toString();
        if (opts.getMustPreserveWhitespace() == false) {
            value = value.trim();
        }
        switch (endElt) {
        case ELT_TITLE: {
            Object t = inItems == false ? (inImage == false ? feedB.title(value) : feedB.imageTitle(value))
                    : currentItemB.title(value);
            break;
        } // channel & image & item
        case ELT_LINK: {
            Object t = inItems == false ? (inImage == false ? feedB.link(value) : feedB.imageLink(value))
                    : currentItemB.link(value);
            break;
        } // channel & image & item
        case ELT_DESCRIPTION: {
            Object t = inItems == false
                    ? (inImage == false ? feedB.description(value) : currentItemB.description(value))
                    : currentItemB.description(value);
            break;
        } // channel & image & item
        case ELT_LANGUAGE:
            feedB.language(value);
            break; // channel
        case ELT_COPYRIGHT:
            feedB.copyright(value);
            break; // channel
        case ELT_MANAGINGEDITOR:
            feedB.managingEditor(value);
            break; // channel
        case ELT_WEBMASTER:
            feedB.webMaster(value);
            break; // channel
        case ELT_PUBDATE: {
            Object t = inItems == false ? feedB.pubDate(value) : currentItemB.pubDate(value);
            break;
        } // channel & item
        case ELT_LASTBUILDDATE:
            feedB.lastBuildDate(value); // channel
        case ELT_CATEGORY: {
            Object t = inItems == false ? feedB.addCategory(value, categoryDomain)
                    : currentItemB.addCategory(value, categoryDomain);
            break;
        } // channel & item
        case ELT_GENERATOR:
            feedB.generator(value);
            break; // channel
        case ELT_DOCS:
            feedB.docs(value);
            break; // channel
        case ELT_CLOUD: // channel // TODO y: yeah...
        case ELT_TTL:
            try {
                feedB.ttl(Integer.parseInt(value));
            } catch (NumberFormatException e) {
                feedB.ttl(Integer.MAX_VALUE);
            }
            break; // channel
        case ELT_IMAGE:
            inImage = false;
            break; // channel
        case ELT_IMAGE_URL:
            feedB.imageUrl(value); // image
        case ELT_IMAGE_WIDTH:
            try {
                feedB.imageWidth(Integer.parseInt(value));
            } catch (NumberFormatException e) {
                feedB.imageWidth(Image.DEFAULT_WIDTH);
            } // image
        case ELT_IMAGE_HEIGHT:
            try {
                feedB.imageHeight(Integer.parseInt(value));
            } catch (NumberFormatException e) {
                feedB.imageHeight(Image.DEFAULT_HEIGHT);
            } // image
        case ELT_RATING:
            feedB.rating(value);
            break; // channel
        // case ELT_SKIPHOURS: // channel // TODO y: ...
        // case ELT_SKIPDAYS: // channel // TODO y: ...
        case ELT_AUTHOR:
            currentItemB.author(value);
            break; // item
        case ELT_COMMENTS:
            currentItemB.comments(value);
            break; // item
        case ELT_GUID:
            currentItemB.guidValue(value);
            break; // item
        case ELT_SOURCE:
            currentItemB.sourceValue(value); // item
        }
        // @formatter:off
    }

    @Override
    Feed getProductFeed() {
        return feedB.build();
    }

}