bbcdataservice.BBCProgrammesParser.java Source code

Java tutorial

Introduction

Here is the source code for bbcdataservice.BBCProgrammesParser.java

Source

/*
 * Copyright Michael Keppler
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program 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 General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package bbcdataservice;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.TimeZone;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.lang.StringUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import tvdataservice.MutableChannelDayProgram;
import tvdataservice.MutableProgram;
import tvdataservice.TvDataUpdateManager;
import devplugin.Channel;
import devplugin.Date;
import devplugin.ProgramFieldType;

public class BBCProgrammesParser extends DefaultHandler {

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); // 2010-10-03T01:10:00+01:00
    private static final SimpleDateFormat DATE_FORMAT_ZULU = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

    private static final int PROGRAMME_TYPE_EPISODE = 1;

    private static final int PROGRAMME_TYPE_SERIES = 2;

    private static final int PROGRAMME_TYPE_BRAND = 3;

    private static StringBuilder mText;

    private static boolean mHasNextDay = false;
    private Channel mChannel;

    private MutableProgram mProgram;

    private int mProgramType = 0;

    private boolean mIgnoreElements;

    private Date mDate;

    private TvDataUpdateManager mUpdateManager;

    private HashMap<Date, MutableChannelDayProgram> mDayPrograms;

    public BBCProgrammesParser(HashMap<Date, MutableChannelDayProgram> dayPrograms, Channel channel, Date date) {
        mChannel = channel;
        mDate = date;
        mDayPrograms = dayPrograms;
        mText = new StringBuilder();
    }

    protected static boolean parse(HashMap<Date, MutableChannelDayProgram> dayPrograms, File file, Channel channel,
            Date date) throws Exception {
        mHasNextDay = false;
        SAXParserFactory fac = SAXParserFactory.newInstance();
        fac.setValidating(false);
        SAXParser sax = fac.newSAXParser();
        sax.parse(file, new BBCProgrammesParser(dayPrograms, channel, date));
        return mHasNextDay;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        mText.append(ch, start, length);
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes)
            throws SAXException {
        try {
            mText.setLength(0);
            if ("programme".equalsIgnoreCase(qName)) {
                String programType = attributes.getValue("type");
                if ("episode".equalsIgnoreCase(programType)) {
                    mProgramType = PROGRAMME_TYPE_EPISODE;
                } else if ("series".equalsIgnoreCase(programType)) {
                    mProgramType = PROGRAMME_TYPE_SERIES;
                } else if ("brand".equalsIgnoreCase(programType)) {
                    mProgramType = PROGRAMME_TYPE_BRAND;
                }
            } else if ("ownership".equalsIgnoreCase(qName) || "display_titles".equalsIgnoreCase(qName)) {
                mIgnoreElements = true;
            } else if ("day".equalsIgnoreCase(qName)) {
                mHasNextDay = attributes.getValue("has_next").equals("1");
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if ("ownership".equalsIgnoreCase(qName) || "display_titles".equalsIgnoreCase(qName)) {
            mIgnoreElements = false;
        }
        if (mIgnoreElements) {
            return;
        }
        try {
            String text = mText.toString().trim();
            if ("start".equalsIgnoreCase(qName)) {
                mProgram = null;
                Date startDate = extractDate(text);
                int startTime = extractTime(text);
                if (startDate != null && startTime >= 0) {
                    mProgram = new MutableProgram(mChannel, startDate, startTime / 60, startTime % 60, true);
                    mProgramType = 0;
                }
            } else if ("end".equalsIgnoreCase(qName)) {
                mProgram.setTimeField(ProgramFieldType.END_TIME_TYPE, extractTime(text));
            } else if ("duration".equalsIgnoreCase(qName)) {
                if (text.length() > 0) {
                    mProgram.setLength(Integer.valueOf(text) / 60);
                }
            } else if ("title".equalsIgnoreCase(qName)) {
                if (mProgramType == PROGRAMME_TYPE_EPISODE) {
                    mProgram.setTextField(ProgramFieldType.EPISODE_TYPE, text);
                    // some episodes don't list their series, so use the episode title as program title
                    if (StringUtils.isEmpty(mProgram.getTitle())) {
                        mProgram.setTitle(text);
                    }
                } else if (mProgramType == PROGRAMME_TYPE_SERIES || mProgramType == PROGRAMME_TYPE_BRAND) {
                    mProgram.setTitle(text);
                }
            } else if ("position".equalsIgnoreCase(qName) && text.length() > 0) {
                if (mProgramType == PROGRAMME_TYPE_EPISODE) {
                    mProgram.setIntField(ProgramFieldType.EPISODE_NUMBER_TYPE, Integer.valueOf(text));
                } else if (mProgramType == PROGRAMME_TYPE_SERIES) {
                    mProgram.setIntField(ProgramFieldType.SEASON_NUMBER_TYPE, Integer.valueOf(text));
                }
            } else if ("expected_child_count".equalsIgnoreCase(qName)) {
                if (text.length() > 0) {
                    if (mProgramType == PROGRAMME_TYPE_SERIES) {
                        mProgram.setIntField(ProgramFieldType.EPISODE_TOTAL_NUMBER_TYPE, Integer.valueOf(text));
                    }
                }
            } else if ("short_synopsis".equalsIgnoreCase(qName)) {
                mProgram.setShortInfo(text);
            } else if ("pid".equalsIgnoreCase(qName)) {
                if (text.length() > 0) {
                    String url = "http://www.bbc.co.uk/programmes/" + text;
                    String oldUrl = mProgram.getTextField(ProgramFieldType.URL_TYPE);
                    if (StringUtils.isEmpty(oldUrl)) {
                        mProgram.setTextField(ProgramFieldType.URL_TYPE, url);
                    }
                }
            } else if ("broadcast".equalsIgnoreCase(qName)) {
                // finish the program itself
                mProgram.setProgramLoadingIsComplete();
                Date date = mProgram.getDate();
                MutableChannelDayProgram dayProgram = mDayPrograms.get(date);
                if (dayProgram == null) {
                    dayProgram = new MutableChannelDayProgram(date, mChannel);
                    mDayPrograms.put(date, dayProgram);
                }
                dayProgram.addProgram(mProgram);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private int extractTime(final String dateTime) {
        Calendar cal = parseDateTime(dateTime);
        if (cal == null) {
            return -1;
        }
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int minute = cal.get(Calendar.MINUTE);
        return hour * 60 + minute;
    }

    /**
     * Extracts the date from a XMLTV time value.
     *
     * @param dateTime
     *          The value to extract the date from.
     * @return The date.
     */
    private Date extractDate(final String dateTime) {
        Calendar cal = parseDateTime(dateTime);
        if (cal == null) {
            return null;
        }
        return new devplugin.Date(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1,
                cal.get(Calendar.DAY_OF_MONTH));
    }

    private synchronized Calendar parseDateTime(final String time) {
        try {
            if (time.endsWith("Z")) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(DATE_FORMAT_ZULU.parse(time.substring(0, time.indexOf("Z"))));
                return calendar;
            }
            String withoutSeparator = time.substring(0, 22) + time.substring(23);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(DATE_FORMAT.parse(withoutSeparator));
            //calendar.setTimeInMillis(calendar.getTimeInMillis() - calendar.getTimeZone().getRawOffset());
            return calendar;
        } catch (ParseException e) {
            // logMessage("invalid time format: " + time);
            return null;
        }
    }

}