org.jajuk.services.startup.StartupEngineService.java Source code

Java tutorial

Introduction

Here is the source code for org.jajuk.services.startup.StartupEngineService.java

Source

/*
 *  Jajuk
 *  Copyright (C) The Jajuk Team
 *  http://jajuk.info
 *
 *  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 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.
 *  
 */
package org.jajuk.services.startup;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import javax.swing.JOptionPane;

import org.apache.commons.lang.StringUtils;
import org.jajuk.base.Device;
import org.jajuk.base.DeviceManager;
import org.jajuk.base.FileManager;
import org.jajuk.base.SearchResult.SearchResultType;
import org.jajuk.events.JajukEvent;
import org.jajuk.events.JajukEvents;
import org.jajuk.events.ObservationManager;
import org.jajuk.services.core.SessionService;
import org.jajuk.services.dj.Ambience;
import org.jajuk.services.dj.AmbienceManager;
import org.jajuk.services.players.QueueModel;
import org.jajuk.services.webradio.WebRadio;
import org.jajuk.services.webradio.WebRadioManager;
import org.jajuk.ui.widgets.InformationJPanel;
import org.jajuk.util.Conf;
import org.jajuk.util.Const;
import org.jajuk.util.Messages;
import org.jajuk.util.UtilFeatures;
import org.jajuk.util.UtilSystem;
import org.jajuk.util.log.Log;

/**
 * Startup facilities for sound engine.
 */
public final class StartupEngineService {
    /** List of items to play at startup. */
    private static List<org.jajuk.base.File> alToPlay = new ArrayList<org.jajuk.base.File>();
    /** File to play. */
    private static org.jajuk.base.File fileToPlay;
    /** Web radio to play. */
    private static WebRadio radio;
    /** Index in the queue of the startup file. */
    private static int index = -1;

    /**
     * Instantiates a new startup engine service.
     */
    private StartupEngineService() {
        // private constructor to hide it from the outside
    }

    /**
     * Launch initial track at startup.
     */
    public static void launchInitialTrack() {
        try {
            String startupMode = Conf.getString(Const.CONF_STARTUP_MODE);
            final File fifo = SessionService.getConfFileByPath(Const.FILE_FIFO);
            // Restore if required
            UtilSystem.recoverFileIfRequired(fifo);
            // User explicitly required nothing to start or he left jajuk stopped
            boolean doNotStartAnything = Const.STARTUP_MODE_NOTHING.equals(startupMode)
                    || Conf.getBoolean(Const.CONF_STARTUP_STOPPED)
                    //  CONF_STARTUP_ITEM is void at first jajuk session and until user launched an item
                    || (Const.STARTUP_MODE_ITEM.equals(startupMode)
                            && StringUtils.isBlank(Conf.getString(Const.CONF_STARTUP_ITEM)))
                    // Void collection
                    || FileManager.getInstance().getElementCount() == 0
                    // FIFO void or not exists
                    || (!fifo.exists() || fifo.length() == 0);
            // Populate item to be started and load the stored queue
            populateStartupItems();
            // Check that the file to play is not null and try to mount its device if required 
            if (!doNotStartAnything && !isWebradioStartup()) {
                checkFileToPlay();
            }
            // Set the index of the file to play within the queue.
            // We still need to compute index of file to play even if we play nothing or a radio
            // because user may do a "play" and the next file index must be ready.
            // However, we don't need to test file availability with checkFileToPlay() method.
            updateIndex();
            // Push the new queue
            boolean bRepeat = Conf.getBoolean(Const.CONF_STATE_REPEAT_ALL);
            QueueModel.insert(UtilFeatures.createStackItems(alToPlay, bRepeat, false), 0);
            // Force queue index because insert increase it so it would be set to queue size after the insert
            QueueModel.setIndex(index);
            // Start the file or the radio
            // If user leaved jajuk in stopped mode, do nothing
            if (!doNotStartAnything && isWebradioStartup() && radio != null) {
                launchRadio();
            } else if (!doNotStartAnything && fileToPlay != null) {
                launchFile();
            }
        } catch (Exception e) {
            Log.error(e);
            Messages.getChoice(Messages.getErrorMessage(23), JOptionPane.DEFAULT_OPTION,
                    JOptionPane.WARNING_MESSAGE);
        }
    }

    /**
     * Launch fileToPlay.
     */
    private static void launchFile() {
        new Thread("Track Startup Thread") {
            @Override
            public void run() {
                QueueModel.goTo(index);
            }
        }.start();
    }

    /**
     * Return whether a webradio startup is required (it may be null if the webradio is unknown by the collection).
     * 
     * @return whether a webradio startup is required
     */
    private static boolean isWebradioStartup() {
        String startupMode = Conf.getString(Const.CONF_STARTUP_MODE);
        if (Conf.getBoolean(Const.CONF_WEBRADIO_WAS_PLAYING)
                && (Const.STARTUP_MODE_LAST_KEEP_POS.equals(startupMode)
                        || Const.STARTUP_MODE_LAST.equals(startupMode))) {
            return true;
        }
        if (Const.STARTUP_MODE_ITEM.equals(startupMode)) {
            String conf = Conf.getString(Const.CONF_STARTUP_ITEM);
            if (conf.matches(SearchResultType.WEBRADIO.name() + ".*")) {
                return true;
            }
        }
        return false;
    }

    /**
     * Restore the queue we got at last session exit.
     */
    private static void restoreQueue() {
        final File fifo = SessionService.getConfFileByPath(Const.FILE_FIFO);
        try {
            UtilSystem.recoverFileIfRequired(fifo);
        } catch (IOException e) {
            Log.error(e);
        }
        if (!fifo.exists()) {
            Log.debug("No fifo file");
        } else {
            try {
                final BufferedReader br = new BufferedReader(
                        new FileReader(SessionService.getConfFileByPath(Const.FILE_FIFO)));
                try {
                    String s = null;
                    for (;;) {
                        s = br.readLine();
                        if (s == null) {
                            break;
                        }
                        final org.jajuk.base.File file = FileManager.getInstance().getFileByID(s);
                        if ((file != null) && file.isReady()) {
                            alToPlay.add(file);
                        }
                    }
                } finally {
                    br.close();
                }
            } catch (final IOException ioe) {
                Log.error(ioe);
            }
        }
    }

    /**
     * Find item to play and build the queue.
     */
    private static void populateStartupItems() {
        String startupMode = Conf.getString(Const.CONF_STARTUP_MODE);
        Ambience ambience = AmbienceManager.getInstance().getSelectedAmbience();
        // an item (track or radio) has been forced by user
        if (Const.STARTUP_MODE_ITEM.equals(startupMode)) {
            String conf = Conf.getString(Const.CONF_STARTUP_ITEM);
            String item = conf.substring(conf.indexOf('/') + 1, conf.length());
            if (conf.matches(SearchResultType.FILE.name() + ".*")) {
                fileToPlay = FileManager.getInstance().getFileByID(item);
                if (fileToPlay == null) {
                    Log.warn("Unknown startup file : " + fileToPlay.getAbsolutePath());
                }
            } else if (conf.matches(SearchResultType.WEBRADIO.name() + ".*")) {
                radio = WebRadioManager.getInstance().getWebRadioByName(item);
                if (radio == null) {
                    Log.warn("Unknown startup webradio : " + radio.getName());
                }
            }
        }
        // We play last item
        else if (Const.STARTUP_MODE_LAST.equals(startupMode)
                || Const.STARTUP_MODE_LAST_KEEP_POS.equals(startupMode)) {
            //Restore the queue in these cases
            restoreQueue();
            // If we were playing a webradio when leaving, launch it
            if (Conf.getBoolean(Const.CONF_WEBRADIO_WAS_PLAYING)) {
                radio = WebRadioManager.getInstance()
                        .getWebRadioByName(Conf.getString(Const.CONF_DEFAULT_WEB_RADIO));
            }
            // last file from beginning or last file keep position
            else {
                index = Conf.getInt(Const.CONF_STARTUP_QUEUE_INDEX);
                if (index >= 0 && index < alToPlay.size()) {
                    fileToPlay = alToPlay.get(index);
                }
            }
        } else if (Const.STARTUP_MODE_NOTHING.equals(startupMode)) {
            //Restore the queue in these cases
            restoreQueue();
        }
        // Shuffle mode
        else if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_SHUFFLE)) {
            // Filter files by ambience or if none ambience matches, perform a global shuffle 
            // ignoring current ambience
            alToPlay = UtilFeatures.filterByAmbience(FileManager.getInstance().getGlobalShufflePlaylist(),
                    ambience);
            if (alToPlay.size() == 0) {
                alToPlay = FileManager.getInstance().getGlobalShufflePlaylist();
            }
            if (alToPlay != null && alToPlay.size() > 0) {
                fileToPlay = alToPlay.get(0);
            }
            // Best of mode
        } else if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_BESTOF)) {
            // Filter files by ambience or if none ambience matches, perform a global best-of selection 
            // ignoring current ambience
            alToPlay = UtilFeatures.filterByAmbience(FileManager.getInstance().getGlobalBestofPlaylist(), ambience);
            if (alToPlay.size() == 0) {
                alToPlay = FileManager.getInstance().getGlobalBestofPlaylist();
            }
            if (alToPlay != null && alToPlay.size() > 0) {
                fileToPlay = alToPlay.get(0);
            }
            // Novelties mode
        } else if (Conf.getString(Const.CONF_STARTUP_MODE).equals(Const.STARTUP_MODE_NOVELTIES)) {
            // Filter files by ambience or if none ambience matches, perform a global novelties selection 
            // ignoring current ambience
            alToPlay = UtilFeatures.filterByAmbience(FileManager.getInstance().getGlobalNoveltiesPlaylist(),
                    ambience);
            if (alToPlay.size() == 0) {
                alToPlay = FileManager.getInstance().getGlobalNoveltiesPlaylist();
            }
            if (alToPlay != null && alToPlay.size() > 0) {
                // shuffle the selection
                Collections.shuffle(alToPlay, UtilSystem.getRandom());
                fileToPlay = alToPlay.get(0);
            } else {
                // Alert user that no novelties have been found
                InformationJPanel.getInstance().setMessage(Messages.getString("Error.127"),
                        InformationJPanel.MessageType.ERROR);
            }
        }
        // If the queue was empty and a file to play is provided, build a new queue
        // with this track alone
        if (alToPlay.size() == 0 && fileToPlay != null) {
            alToPlay.add(fileToPlay);
        }
    }

    /**
     * Check that the file can actually be played and handle errors if it's not the case.
     * 
     * @return whether the file can actually be played
     */
    private static boolean checkFileToPlay() {
        boolean result = true;
        // Try to mount the file to play
        if (fileToPlay != null) {
            if (!fileToPlay.isReady()) {
                // File exists but is not mounted, just notify the error
                // without annoying dialog at each startup try to mount
                // device
                Log.debug("Startup file located on an unmounted device" + ", try to mount it");
                try {
                    fileToPlay.getDevice().mount(false);
                    Log.debug("Mount OK");
                } catch (final Exception e) {
                    Log.debug("Mount failed");
                    final Properties pDetail = new Properties();
                    pDetail.put(Const.DETAIL_CONTENT, fileToPlay);
                    pDetail.put(Const.DETAIL_REASON, "10");
                    ObservationManager.notify(new JajukEvent(JajukEvents.PLAY_ERROR, pDetail));
                    result = false;
                }
            }
        } else {
            // file no more exists
            Messages.getChoice(Messages.getErrorMessage(23), JOptionPane.DEFAULT_OPTION,
                    JOptionPane.WARNING_MESSAGE);
            // no more first file, we ignore any stored fifo as it may contains
            // others disappeared files
            result = false;
        }
        return result;
    }

    /**
     * Set index of fileToPlay among alToPlay list.
     */
    private static void updateIndex() {
        // keep index from configuration if already set
        if (index != -1) {
            return;
        }
        // fileToPlay is null if nothing has to be played, then we keep default index value (0)
        if (fileToPlay != null) {
            // find the index of last played track
            index = -1;
            for (int i = 0; i < alToPlay.size(); i++) {
                if (fileToPlay.getID().equals(alToPlay.get(i).getID())) {
                    index = i;
                    break;
                }
            }
            if (index == -1) {
                // Track not stored, push it first
                alToPlay.add(0, fileToPlay);
                index = 0;
            }
        }
    }

    /**
     * Launch the startup webradio.
     */
    private static void launchRadio() {
        new Thread("WebRadio launch thread") {
            @Override
            public void run() {
                QueueModel.launchRadio(radio);
            }
        }.start();
    }

    /**
     * Auto-Mount required devices.
     */
    public static void autoMount() {
        for (final Device device : DeviceManager.getInstance().getDevices()) {
            if (device.getBooleanValue(Const.XML_DEVICE_AUTO_MOUNT)) {
                try {
                    device.mount(false);
                } catch (final Exception e) {
                    Log.error(112, device.getName(), e);
                    continue;
                }
            }
        }
    }
}