primarydatamanager.PrimaryDataManager.java Source code

Java tutorial

Introduction

Here is the source code for primarydatamanager.PrimaryDataManager.java

Source

/*
 * TV-Browser
 * Copyright (C) 04-2003 Martin Oberhauser (darras@users.sourceforge.net)
 *
 * 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-08-14 19:33:47 +0200 (Sat, 14 Aug 2010) $
 *   $Author: jo_mormes $
 * $Revision: 6700 $
 */
package primarydatamanager;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.lang.StringUtils;

import primarydatamanager.primarydataservice.PrimaryDataService;
import tvbrowserdataservice.file.ChannelList;
import tvbrowserdataservice.file.DayProgramFile;
import tvbrowserdataservice.file.SummaryFile;
import util.io.FileFormatException;
import util.io.IOUtilities;
import util.io.Mirror;
import util.io.VerySimpleFormatter;
import devplugin.ChannelGroup;
import devplugin.Date;

/**
 *
 *
 * @author Til Schneider, www.murfman.de
 */
public class PrimaryDataManager {

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

    private File mRawDir;
    private File mPreparedDir;
    private File mWorkDir;
    private File mBackupDir;
    private File mConfigDir;

    private ChannelList[] mChannelListArr;
    private String[] mGroupNameArr;

    private RawDataProcessor mRawDataProcessor;

    private static RandomAccessFile mLockFile;

    private static FileLock mLock;

    public PrimaryDataManager(File baseDir) throws PreparationException {
        Logger.getLogger("sun.awt.X11.timeoutTask.XToolkit").setLevel(Level.INFO);
        mRawDir = new File(baseDir, "raw");
        mPreparedDir = new File(baseDir, "prepared");
        mWorkDir = new File(baseDir, "temp");
        mBackupDir = new File(baseDir, "backup");
        mConfigDir = new File(baseDir, "config");
        mRawDataProcessor = new RawDataProcessor();
    }

    public void setGroupNames(String[] groupNames) {
        mChannelListArr = new ChannelList[groupNames.length];
        mGroupNameArr = groupNames;
    }

    public void forceCompleteUpdateFor(String channel) {
        mRawDataProcessor.forceCompleteUpdateFor(channel);
    }

    public void createGroupFiles() throws PreparationException {

        /* A groupname file contains the name of the group in
         * an internationalized form */
        for (String group : mGroupNameArr) {
            File fromFile = new File(mConfigDir, group + ".txt");
            File toFile = new File(mWorkDir, group + "_info");
            try {
                IOUtilities.copy(fromFile, toFile);
            } catch (IOException exc) {
                throw new PreparationException("Could not copy file from " + fromFile.getAbsolutePath() + " to "
                        + toFile.getAbsolutePath(), exc);
            }
        }

    }

    public void updateRawDataDir() throws PreparationException {
        // Delete the old work directory
        try {
            IOUtilities.deleteDirectory(mWorkDir);
        } catch (IOException exc) {
            throw new PreparationException("Deleting old work directory failed", exc);
        }

        // Create a new work directory
        if (!mWorkDir.mkdir()) {
            throw new PreparationException("Could not create work directory: " + mWorkDir.getAbsolutePath());
        }

        // Create a new raw directory if it does not exist
        if (!mRawDir.exists()) {
            if (!mRawDir.mkdir()) {
                throw new PreparationException("Could not create raw directory: " + mRawDir.getAbsolutePath());
            }
        }

        //Create the channel list file
        createChannelList();

        // Update the mirror lists
        updateMirrorList();

        // Process the new raw data
        for (int i = 0; i < mGroupNameArr.length; i++) {
            mRawDataProcessor.processRawDataDir(mRawDir, mPreparedDir, mWorkDir, mChannelListArr[i]);
        }

        // Create a summary files
        createSummaryFile();
        createGroupFiles();

        // Delete the old backup
        try {
            IOUtilities.deleteDirectory(mBackupDir);
        } catch (IOException exc) {
            throw new PreparationException("Deleting old backup directory failed", exc);
        }

        // Let the prepared dir become the new backup
        if (mPreparedDir.exists()) {
            if (!mPreparedDir.renameTo(mBackupDir)) {
                throw new PreparationException("Renaming file '" + mPreparedDir.getAbsolutePath() + "' to '"
                        + mBackupDir.getAbsolutePath() + "' failed");
            }
        }

        // Let the work dir become the new prepared dir
        if (!mWorkDir.renameTo(mPreparedDir)) {
            throw new PreparationException("Renaming file '" + mWorkDir.getAbsolutePath() + "' to '"
                    + mPreparedDir.getAbsolutePath() + "' failed");
        }

        // Print out the statistics

        int quarantineCount = mRawDataProcessor.getQuarantineCount();
        if (quarantineCount > 0) {
            mLog.warning(quarantineCount + " day programs where put into quarantine");

            File txtDir = new File(mPreparedDir, "quarantine");
            if (!txtDir.exists()) {
                System.out.println("file " + txtDir.getAbsolutePath() + " does not exist");
            }
            if (!txtDir.isDirectory()) {
                System.out.println("file " + txtDir.getAbsolutePath() + " is not a directory");
            }

            if (txtDir.exists() && txtDir.isDirectory()) {
                File destDir = new File(txtDir, "txt");
                destDir.mkdirs();
                try {
                    DayProgramFileTranslator.translateAllDayPrograms(txtDir);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (FileFormatException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static PrimaryDataService createPrimaryDataService(String className) throws PreparationException {
        Class clazz;

        if (className.startsWith(".")) {
            className = "primarydatamanager.primarydataservice.secret" + className;
        }

        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException exc) {
            throw new PreparationException("Primary data service class does not exist: " + className, exc);
        }

        Object obj;
        try {
            obj = clazz.newInstance();
        } catch (Exception exc) {
            throw new PreparationException("Can't create instance of primary data " + "service class: " + className,
                    exc);
        }

        if (obj instanceof PrimaryDataService) {
            return (PrimaryDataService) obj;
        } else {
            throw new PreparationException(
                    "Class " + className + " does not implement " + PrimaryDataService.class.getName());
        }
    }

    private void createChannelList() throws PreparationException {
        mLog.fine("Updating the channel list");

        for (int i = 0; i < mGroupNameArr.length; i++) {
            // Load the channellist.txt
            mChannelListArr[i] = loadChannelListTxt(mGroupNameArr[i] + "_channellist.txt");

            // Save the mirrorlist.gz
            File toFile = new File(mWorkDir, mGroupNameArr[i] + "_" + ChannelList.FILE_NAME);
            try {
                mChannelListArr[i].writeToFile(toFile);
            } catch (Exception exc) {
                throw new PreparationException("Writing channel list for group " + mGroupNameArr[i] + " failed",
                        exc);
            }
        }
    }

    private void createSummaryFile() throws PreparationException {

        for (int i = 0; i < mGroupNameArr.length; i++) {

            // Create the file
            SummaryFile summary = new SummaryFile();
            File[] fileArr = mWorkDir.listFiles();
            for (File file : fileArr) {
                String fileName = file.getName();
                if (fileName.endsWith("_full.prog.gz")) {
                    // This is a complete file -> Put its version to the summary
                    try {
                        Date date = DayProgramFile.getDateFromFileName(fileName);
                        String country = DayProgramFile.getCountryFromFileName(fileName);
                        String channelId = DayProgramFile.getChannelNameFromFileName(fileName);
                        String levelName = DayProgramFile.getLevelFromFileName(fileName);

                        //if (channelBelongsToGroup(channelId, country)) {
                        if (RawDataProcessor.channelBelongsToGroup(mChannelListArr[i], channelId, country)) {
                            int level = DayProgramFile.getLevelIndexForId(levelName);
                            if (level == -1) {
                                throw new PreparationException("Day program file has unknown level '" + levelName
                                        + "': " + file.getAbsolutePath());
                            }
                            int version = DayProgramFile.readVersionFromFile(file);

                            summary.setDayProgramVersion(date, country, channelId, level, version);
                        }
                    } catch (Exception exc) {
                        throw new PreparationException(
                                "Adding day program file to summary " + "failed: " + file.getAbsolutePath(), exc);
                    }
                }
            }

            System.out.println("writing summary to file...");

            // Save the file
            File file = new File(mWorkDir, mGroupNameArr[i] + "_" + SummaryFile.SUMMARY_FILE_NAME);
            try {
                summary.writeToFile(file);
            } catch (Exception exc) {
                throw new PreparationException("Writing summary file failed: " + file.getAbsolutePath(), exc);
            }
        }

        System.out.println("done.");
    }

    private void updateMirrorList() throws PreparationException {
        mLog.fine("Updating the mirror list");

        for (String groupNameArr : mGroupNameArr) {
            // Load the mirrorlist.txt
            Mirror[] mirrorArr = loadMirrorListTxt(groupNameArr + "_mirrorlist.txt");

            // Save the mirrorlist.gz
            File toFile = new File(mWorkDir, groupNameArr + "_" + Mirror.MIRROR_LIST_FILE_NAME);
            try {
                Mirror.writeMirrorListToFile(toFile, mirrorArr);
            } catch (IOException exc) {
                throw new PreparationException("Writing mirror list for group " + groupNameArr + " failed", exc);
            }
        }
    }

    private ChannelList loadChannelListTxt(String fileName) throws PreparationException {
        ChannelList result = new ChannelList((ChannelGroup) null);

        File fromFile = new File(mConfigDir, fileName);
        try {
            result.readFromStream(new FileInputStream(fromFile), null, false);
        } catch (IOException e) {
            throw new PreparationException("Loading " + fileName + " failed", e);
        } catch (FileFormatException e) {
            throw new PreparationException("Loading " + fileName + " failed", e);
        }

        return result;

    }

    private Mirror[] loadMirrorListTxt(String fileName) throws PreparationException {
        ArrayList<Mirror> mirrorList = new ArrayList<Mirror>();

        File fromFile = new File(mConfigDir, fileName);
        BufferedInputStream stream = null;
        try {
            stream = new BufferedInputStream(new FileInputStream(fromFile), 0x4000);
            BufferedReader reader = new BufferedReader(new InputStreamReader(stream));

            String line;
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                int weight = 100;
                if (StringUtils.isNotEmpty(line)) {
                    String url = line;
                    String[] s = url.split(";");
                    if (s.length == 2) {
                        url = s[0];
                        String weightStr = s[1];
                        try {
                            weight = Integer.parseInt(weightStr);
                        } catch (NumberFormatException e) {
                            weight = 100;
                            mLog.warning(
                                    "Invalid weight entry in " + fileName + ": " + line + " - set to 100 instead");
                        }
                    }
                    mirrorList.add(new Mirror(url, weight));
                }
            }
        } catch (Exception exc) {
            throw new PreparationException("Loading " + fileName + " failed", exc);
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException exc) {
                    //Empty
                }
            }
        }

        // Convert the list into an array
        Mirror[] mirrorArr = new Mirror[mirrorList.size()];
        mirrorList.toArray(mirrorArr);

        return mirrorArr;
    }

    /**
     * @return <code>true</code>, if the prepared directory exists
     */
    private boolean doesPreparedExist() {
        return mPreparedDir.exists() && mPreparedDir.isDirectory();
    }

    /**
     * Create the .lock file in the config directory
     * @return false, if the .lock file exist and is locked or cannot be locked.
     */
    private boolean createLockFile() {

        File lockFile = new File(mConfigDir, ".lock");

        if (lockFile.exists()) {
            try {
                mLockFile = new RandomAccessFile(lockFile.toString(), "rw");
                mLock = mLockFile.getChannel().tryLock();

                if (mLock == null) {
                    return false;
                }
            } catch (Exception e) {
                return false;
            }
        } else {
            try {
                lockFile.createNewFile();
                mLockFile = new RandomAccessFile(lockFile.toString(), "rw");
                mLock = mLockFile.getChannel().tryLock();
            } catch (Exception e) {
                if (e instanceof IOException) {
                    mLog.log(Level.WARNING, e.getLocalizedMessage(), e);
                }
            }
        }

        return true;
    }

    private void deleteLockFile() {
        File lockFile = new File(mConfigDir, ".lock");

        try {
            mLock.release();
        } catch (Exception e) {
            // ignore
        }

        try {
            mLockFile.close();
        } catch (Exception e) {
            // ignore
        }

        lockFile.delete();
    }

    public static void main(String[] args) {
        // setup logging
        try {
            // Get the default Logger
            Logger mainLogger = Logger.getLogger("");
            mainLogger.setLevel(Level.FINEST);

            Handler consoleHandler = mainLogger.getHandlers()[0];
            consoleHandler.setLevel(Level.FINEST);
            consoleHandler.setFormatter(new VerySimpleFormatter());

            // Add a file handler
            new File("log").mkdir();
            Handler fileHandler = new FileHandler("log/datamanager.log", 50000, 2, true);
            fileHandler.setLevel(Level.INFO);
            mainLogger.addHandler(fileHandler);
        } catch (IOException exc) {
            System.out.println("Can't create log file");
            exc.printStackTrace();
        }

        // Start the update
        if (args.length == 0) {
            System.out.println("USAGE: PrimaryDataManager [-forceCompleteUpdate [channel{;channel}]] groups...");
            System.exit(1);
        } else {
            try {
                PrimaryDataManager manager = new PrimaryDataManager(new File("."));
                ArrayList<String> groupNames = new ArrayList<String>();
                for (int i = 0; i < args.length; i++) {
                    if (args[i].equalsIgnoreCase("-forceCompleteUpdate")) {
                        if ((i + 1) >= args.length) {
                            System.out.println("You have to specify a colon separated "
                                    + "list of channels after -forceCompleteUpdate");
                            System.exit(1);
                        } else {
                            i++;
                            StringTokenizer tokenizer = new StringTokenizer(args[i], ":");
                            while (tokenizer.hasMoreTokens()) {
                                manager.forceCompleteUpdateFor(tokenizer.nextToken());
                            }
                        }
                    } else {
                        final String[] groups = args[i].split(",");
                        groupNames.addAll(Arrays.asList(groups));
                    }
                }

                if (groupNames.size() == 0) {
                    System.out.println("Please specify at least one channel group");
                    System.exit(-1);
                }

                if (!manager.doesPreparedExist()) {
                    System.out.println(
                            "The prepared directory is missing, this directory is very important and shouldn't "
                                    + "be deleted, because this leeds to massiv problems.");
                    System.exit(-1);
                }

                if (!manager.createLockFile()) {
                    System.out.println("The PrimaryDataManager is already running.");
                    System.exit(-1);
                }

                String[] groupNamesArr = new String[groupNames.size()];
                groupNames.toArray(groupNamesArr);
                manager.setGroupNames(groupNamesArr);

                manager.updateRawDataDir();

                manager.deleteLockFile();

                // Exit with error code 2 if some day programs were put into quarantine
                if (manager.mRawDataProcessor.getQuarantineCount() != 0) {
                    System.exit(2);
                }
            } catch (PreparationException exc) {
                exc.printStackTrace();
                System.exit(1);
            }
        }
    }

}