Package tvbrowserdataservice

Source Code of tvbrowserdataservice.TvBrowserDataServiceChannelGroup

/*
* TV-Browser
* Copyright (C) 04-2003 Martin Oberhauser (martin@tvbrowser.org)
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* CVS information:
*  $RCSfile$
*   $Source$
*     $Date: 2010-05-02 20:34:40 +0200 (Sun, 02 May 2010) $
*   $Author: bananeweizen $
* $Revision: 6612 $
*/

package tvbrowserdataservice;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import tvbrowserdataservice.file.ChannelList;
import tvbrowserdataservice.file.SummaryFile;
import util.exc.TvBrowserException;
import util.io.FileFormatException;
import util.io.IOUtilities;
import util.io.Mirror;
import util.io.stream.InputStreamProcessor;
import util.io.stream.StreamUtilities;
import devplugin.Channel;
import devplugin.ChannelGroupImpl;
import devplugin.ProgressMonitor;

/**
* The ChannelGroup implementation of the TvBrowserDataService
*/
public class TvBrowserDataServiceChannelGroup extends ChannelGroupImpl {

  private String[] mMirrorUrlArr;

  private File mDataDir;

  private Channel[] mAvailableChannelArr;

  private Mirror mCurMirror;

  private SummaryFile mSummary;

  private String mName = null;

  private TvBrowserDataService mDataService;

  private HashSet<Channel> mChannels;

  /**
   * Settings for storing changes in ProviderName/Id
   */
  private TvBrowserDataServiceSettings mSettings;

  private static final Logger mLog = Logger.getLogger(TvBrowserDataServiceChannelGroup.class.getName());

  /** The localizer for this class. */
  private static final util.ui.Localizer mLocalizer = util.ui.Localizer
      .getLocalizerFor(TvBrowserDataServiceChannelGroup.class);

  private static final int MAX_META_DATA_AGE = 2;

  /**
   * Creates a new ChannelGroup
   *
   * @param dataservice The data service of the group.
   * @param id The id of the group.
   * @param name The name of the group.
   * @param description The description for the group.
   * @param provider The provider of the group.
   * @param mirrorUrls The mirror urls of the group.
   * @param settings The properties of the group.
   */
  public TvBrowserDataServiceChannelGroup(TvBrowserDataService dataservice, String id, String name, String description, String provider, String[] mirrorUrls, TvBrowserDataServiceSettings settings) {
    super(id, name, description, provider);
    mName = name;
    mDataService = dataservice;
    mMirrorUrlArr = mirrorUrls;
    mChannels = new HashSet<Channel>();
    mDataDir = dataservice.getDataDir();
    mSettings = settings;
  }

  /**
   * Creates a new ChannelGroup
   *
   * @param dataservice The data service of the group.
   * @param id The id of the group.
   * @param mirrorUrls The mirror urls of the group.
   * @param settings The properties of the group.
   */
  public TvBrowserDataServiceChannelGroup(TvBrowserDataService dataservice, String id, String[] mirrorUrls, TvBrowserDataServiceSettings settings) {
    this(dataservice, id, null, null, null, mirrorUrls, settings);
  }


  protected String[] getMirrorArr() {
    return mMirrorUrlArr;
  }

  /**
   * Sets the data directory.
   *
   * @param dataDir The data directory.
   */
  public void setWorkingDirectory(File dataDir) {
    mDataDir = dataDir;
  }

  /**
   * Add a channel to this group.
   *
   * @param ch The channel to add.
   */
  public void addChannel(Channel ch) {
    mChannels.add(ch);
  }

  /**
   * Get all channels.
   *
   * @return An Iterator with the channels.
   */
  public Iterator<Channel> getChannels() {
    return mChannels.iterator();
  }

  private String getLocaleProperty(Properties prop, String key, String defaultValue) {
    Locale locale = Locale.getDefault();
    String language = locale.getLanguage();
    String result = prop.getProperty(new StringBuilder(key).append('_').append(
        language).toString());
    if (result == null) {
      result = prop.getProperty(new StringBuilder(key).append("_default")
          .toString(), defaultValue);
    }
    return result;

  }

  public String getDescription() {
    if (mDescription != null) {
      return mDescription;
    }

    File file = new File(mDataDir, getId() + "_info");
    if (!file.exists()) { return ""; }
    final Properties prop = new Properties();
    // TODO init all props at once
    StreamUtilities.inputStreamIgnoringExceptions(file,
        new InputStreamProcessor() {
          public void process(InputStream input) throws IOException {
            prop.load(input);
          }
        });
    mDescription = getLocaleProperty(prop, "description", "");
    return mDescription;
  }

  public String getName() {
    if (mName != null) { return mName; }

    File file = new File(mDataDir, getId() + "_info");
    if (!file.exists()) { return getId(); }

    final Properties prop = new Properties();
    try {
      StreamUtilities.inputStream(file, new InputStreamProcessor() {
        public void process(InputStream input) throws IOException {
          prop.load(input);
        }
      });
      Locale locale = Locale.getDefault();
      String language = locale.getLanguage();
      String result = prop.getProperty(language);
      if (result == null) {
        result = prop.getProperty("default", getId());
      }
      return result;

    } catch (IOException e) {
      return getId();
    }

  }


  public String getProviderName() {
    if (mProvider != null) {
      return mProvider;
    }
    String providerName = mSettings.getProvider(getId());
    if (providerName != null) {
      mProvider = providerName;
      return providerName;
    }
    File file = new File(mDataDir, getId() + "_info");
    if (!file.exists()) { return ""; }
    final Properties prop = new Properties();
    try {
      StreamUtilities.inputStream(file, new InputStreamProcessor() {
        public void process(InputStream input) throws IOException {
          prop.load(input);
        }
      });
      providerName = prop.getProperty("provider",mLocalizer.msg("unknownProvider","unknown"));
      mSettings.setProvider(getId(), providerName);
      mProvider = providerName;
      return providerName;
    } catch (IOException e) {
      mLog.log(Level.SEVERE, "Could not read provider name",e);
      return mLocalizer.msg("unknownProvider","unknown");
    }
  }

  @Override
  public String toString() {
    return getName();
  }

  protected void chooseMirrors() throws TvBrowserException {
    // load the mirror list
    Mirror[] serverDefindeMirros = getServerDefinedMirrors();
    Mirror[] mirrorArr = Mirror.loadMirrorList(new File(mDataDir, getId() + "_" + Mirror.MIRROR_LIST_FILE_NAME), mMirrorUrlArr, serverDefindeMirros);

    // Get a random Mirror that is up to date
    mCurMirror = Mirror.chooseUpToDateMirror(mirrorArr, null, getName(), getId(), TvBrowserDataServiceChannelGroup.class, " Please contact the TV data provider for help.");

    if (mCurMirror != null) {
      mLog.info("Using mirror " + mCurMirror.getUrl());

      // Update the mirrorlist (for the next time)
      updateMetaFile(mCurMirror.getUrl(), getId() + "_" + Mirror.MIRROR_LIST_FILE_NAME);

      // Update the channel list
      // NOTE: We have to load the channel list before the programs, because
      // we need it for the programs.
      updateChannelList(mCurMirror, false);

      try {
        mSummary = loadSummaryFile(mCurMirror);
      } catch (Exception exc) {
        mLog.log(Level.WARNING, "Getting summary file from mirror " + mCurMirror.getUrl() + " failed.", exc);
        mSummary = null;
      }
    }
    else {
      mLog.info("No up to date mirror available for "+getId());
    }
  }

  /**
   * @return The summary file.
   */
  public SummaryFile getSummary() {
    return mSummary;
  }

  /**
   * Get the current mirror.
   *
   * @return The current mirror.
   */
  public Mirror getMirror() {
    return mCurMirror;
  }

  private SummaryFile loadSummaryFile(Mirror mirror) throws IOException, FileFormatException {
    String url = mirror.getUrl() + (mirror.getUrl().endsWith("/") ? "" : "/") + getId() + "_" + SummaryFile.SUMMARY_FILE_NAME;

    InputStream stream = null;
    try {
      stream = IOUtilities.getStream(new URL(url));

      SummaryFile summary = new SummaryFile();
      summary.readFromStream(stream, null);

      return summary;
    } finally {
      if (stream != null) {
        stream.close();
      }
    }
  }

  protected void setBaseMirror(String[] mirrorUrl) {
    mMirrorUrlArr = mirrorUrl;
  }

  private Mirror[] getServerDefinedMirrors() {
    File groupFile = new File(mDataDir, TvBrowserDataService.CHANNEL_GROUPS_FILENAME);
    Mirror[] mirrorArr = null;

    if (!groupFile.exists()) {
      mLog.info("Group file '"+TvBrowserDataService.CHANNEL_GROUPS_FILENAME+"' does not exist");
    } else {
      BufferedReader in = null;

      try {
        in = new BufferedReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(groupFile), 0x1000), "utf-8"));
        String line = in.readLine();
        while (line != null) {
          String[] s = line.split(";");

          if (s.length>=5 && s[0].compareTo(getId()) == 0) {
            int n = s.length-4;
            mirrorArr = new Mirror[n];

            for(int i = 0; i < n; i++) {
              mirrorArr[i] = new Mirror(s[i+4], 1);
            }

            break;
          }

          line = in.readLine();
        }
        in.close();
      } catch (IOException e) {
        mLog.log(Level.SEVERE, "Could not read group list "+TvBrowserDataService.CHANNEL_GROUPS_FILENAME, e);
      }
      finally {
        if(in != null) {
          try {
            in.close();
          }catch(Exception ee) {}
        }
      }
    }

    return mirrorArr;
  }

  private boolean needsUpdate(File file) {
    if (!file.exists()) {
      return true;
    } else {
      long minLastModified = System.currentTimeMillis() - (MAX_META_DATA_AGE * 24L * 60L * 60L * 1000L);
      return file.lastModified() < minLastModified;
    }
  }

  private void updateMetaFile(String serverUrl, String metaFileName) throws TvBrowserException {
    File file = new File(mDataDir, metaFileName);

    // Download the new file if needed
    if (needsUpdate(file)) {
      String url = serverUrl + "/" + metaFileName;
      mLog.fine("Updating Metafile " + url);
      try {
        IOUtilities.download(new URL(url), file);
      } catch (IOException exc) {
        throw new TvBrowserException(getClass(), "error.1", "Downloading file from '{0}' to '{1}' failed", url, file
                .getAbsolutePath(), exc);
      }
    }
  }

  private void updateChannelList(Mirror mirror, boolean forceUpdate) throws TvBrowserException {
    String fileName = getId() + "_" + ChannelList.FILE_NAME;
    File file = new File(mDataDir, fileName + ".new");
    if (forceUpdate || needsUpdate(file)) {
      String url = mirror.getUrl() + (mirror.getUrl().endsWith("/") ? "" : "/") + fileName;
      try {
        IOUtilities.download(new URL(url), file);
        if (file.canRead() && file.length() > 0) {
          // try reading the file
          devplugin.ChannelGroup group = new devplugin.ChannelGroupImpl(getId(), getName(), null, getProviderName());
          ChannelList channelList = new ChannelList(group);
          channelList.readFromFile(file, mDataService);
          // ok, we can read it, so use this new file instead of the old
          File oldFile = new File(mDataDir, fileName);
          oldFile.delete();
          file.renameTo(oldFile);
          // Invalidate the channel list
          mAvailableChannelArr = null;
        }
      } catch (Exception exc) {
        throw new TvBrowserException(getClass(), "error.4", "Server has no channel list: {0}", mirror.getUrl(), exc);
      }
    }
  }

  /**
   * Checks and returns the available channels of this group.
   *
   * @param monitor The progress monitor that is to be used.
   * @return The available channel array.
   * @throws TvBrowserException
   */
  public Channel[] checkForAvailableChannels(ProgressMonitor monitor) throws TvBrowserException {
    // load the mirror list
    Mirror[] serverDefindeMirros = getServerDefinedMirrors();
    Mirror[] mirrorArr = Mirror.loadMirrorList(new File(mDataDir, getId() + "_" + Mirror.MIRROR_LIST_FILE_NAME), mMirrorUrlArr, serverDefindeMirros);

    // Get a random Mirror that is up to date
    Mirror mirror = Mirror.chooseUpToDateMirror(mirrorArr, monitor, getName(), getId(), TvBrowserDataServiceChannelGroup.class, " Please contact the TV data provider for help.");

    if(mirror != null) {
      mLog.info("Using mirror " + mirror.getUrl());

      // Update the mirrorlist (for the next time)
      updateMetaFile(mirror.getUrl(), getId() + "_" + Mirror.MIRROR_LIST_FILE_NAME);

      // Update the groupname file
      updateMetaFile(mirror.getUrl(), getId() + "_info");

      // Update the channel list
      updateChannelList(mirror, true);
      return getAvailableChannels();
    }
    else {
      return new Channel[0];
    }
  }

  /**
   * Gets the list of the channels that are available by this data service.
   *
   * @return The available channel array.
   */
  public synchronized Channel[] getAvailableChannels() {
    if (mAvailableChannelArr == null) {
      File channelFile = new File(mDataDir, getId() + "_" + ChannelList.FILE_NAME);
      if (channelFile.exists()) {
        try {
          devplugin.ChannelGroup group = new devplugin.ChannelGroupImpl(getId(), getName(), null, getProviderName());
          ChannelList channelList = new ChannelList(group);
          channelList.readFromFile(channelFile, mDataService);
          mAvailableChannelArr = channelList.createChannelArray();
        } catch (Exception exc) {
          mLog.log(Level.WARNING, "Loading channellist failed: " + channelFile.getAbsolutePath(), exc);
        }
      }

      if (mAvailableChannelArr == null) {
        // There is no channel file or loading failed
        // -> create a list without any channels
        mLog.warning("No channels available for group '"+getId()+"' no channellist available?");
        mAvailableChannelArr = new Channel[] {};
      }
    }

    return mAvailableChannelArr;
  }

  /**
   * delete all the files created by this channel group,
   * only to be called on deletion of a channel group
   * @since 2.6
   */
  public void deleteAllFiles() {
    File channelFile = new File(mDataDir, getId() + "_" + ChannelList.FILE_NAME);
    if (channelFile.exists()) {
      try {
        channelFile.delete();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    File mirrorFile = new File(mDataDir, getId() + "_" + Mirror.MIRROR_LIST_FILE_NAME);
    if (mirrorFile.exists()) {
      try {
        mirrorFile.delete();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    File infoFile = new File(mDataDir, getId() + "_info");
    if (infoFile.exists()) {
      try {
        infoFile.delete();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}
TOP

Related Classes of tvbrowserdataservice.TvBrowserDataServiceChannelGroup

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.