/* * 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.base; import java.io.IOException; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; import org.jajuk.events.JajukEvent; import org.jajuk.events.JajukEvents; import org.jajuk.events.Observer; import org.jajuk.util.Const; import org.jajuk.util.MD5Processor; import org.jajuk.util.Messages; import org.jajuk.util.ReadOnlyIterator; import org.jajuk.util.UtilSystem; import org.jajuk.util.error.JajukException; import org.jajuk.util.log.Log; /** * Convenient class to manage playlists. */ public final class PlaylistManager extends ItemManager implements Observer { /** Self instance. */ private static PlaylistManager singleton = new PlaylistManager(); /** * No constructor available, only static access. */ private PlaylistManager() { super(); // ---register properties--- // ID registerProperty(new PropertyMetaInformation(Const.XML_ID, false, true, false, false, false, String.class, null)); // Name registerProperty(new PropertyMetaInformation(Const.XML_NAME, false, true, true, true, false, String.class, null)); // Directory registerProperty(new PropertyMetaInformation(Const.XML_DIRECTORY, false, true, true, false, false, String.class, null)); } /** * Gets the instance. * * @return singleton */ public static PlaylistManager getInstance() { return singleton; } /** * Register an Playlist with a known id. * * @param fio * @param dParentDirectory * * @return the playlist */ Playlist registerPlaylistFile(java.io.File fio, Directory dParentDirectory) { String sId = createID(fio.getName(), dParentDirectory); return registerPlaylistFile(sId, fio.getName(), dParentDirectory); } /** * Creates the id. * * @param sName * @param dParentDirectory * * @return ItemManager ID */ protected static String createID(String sName, Directory dParentDirectory) { return MD5Processor.hash(new StringBuilder(dParentDirectory.getDevice().getName()) .append(dParentDirectory.getRelativePath()).append(sName).toString()); } /** * Remove a playlist. * * @param plf the playlist * * @throws IOException Signals that an I/O exception has occurred. */ private void removePlaylistFile(Playlist plf) throws IOException { String sFileToDelete = plf.getDirectory().getFio().getAbsoluteFile().toString() + java.io.File.separatorChar + plf.getName(); lock.writeLock().lock(); try { java.io.File fileToDelete = new java.io.File(sFileToDelete); if (fileToDelete.exists()) { UtilSystem.deleteFile(fileToDelete); } // remove playlist removeItem(plf); } finally { lock.writeLock().unlock(); } } /** * Delete physically a playlist. * * @param plf the playlist * * @throws IOException Signals that an I/O exception has occurred. */ public void deletePlaylistFile(Playlist plf) throws IOException { lock.writeLock().lock(); try { String sFileToDelete = plf.getDirectory().getFio().getAbsoluteFile().toString() + java.io.File.separatorChar + plf.getName(); java.io.File fileToDelete = new java.io.File(sFileToDelete); if (fileToDelete.exists()) { UtilSystem.deleteFile(fileToDelete); } // remove playlist removePlaylistFile(plf); } finally { lock.writeLock().unlock(); } } /** * Register an Playlist with a known id. * * @param sId * @param sName * @param dParentDirectory * @return the playlist */ public Playlist registerPlaylistFile(String sId, String sName, Directory dParentDirectory) { Playlist playlistFile = getPlaylistByID(sId); if (playlistFile != null) { return playlistFile; } playlistFile = new Playlist(sId, sName, dParentDirectory); registerItem(playlistFile); return playlistFile; } /** * Clean all references for the given device. * * @param sId : * Device id */ public void cleanDevice(String sId) { for (Playlist plf : getPlaylists()) { if (plf.getDirectory() == null || plf.getDirectory().getDevice().getID().equals(sId)) { removeItem(plf); } } } /* * (non-Javadoc) * * @see org.jajuk.base.ItemManager#getIdentifier() */ @Override public String getXMLTag() { return Const.XML_PLAYLIST_FILES; } /** * Change a playlist name. * * @param plfOld * @param sNewName * * @return new playlist * * @throws JajukException the jajuk exception */ Playlist changePlaylistFileName(Playlist plfOld, String sNewName) throws JajukException { lock.writeLock().lock(); try { // check given name is different if (plfOld.getName().equals(sNewName)) { return plfOld; } // check if this file still exists if (!plfOld.getFIO().exists()) { throw new JajukException(135); } java.io.File ioNew = new java.io.File(plfOld.getFIO().getParentFile().getAbsolutePath() + java.io.File.separator + sNewName); // recalculate file ID plfOld.getDirectory(); String sNewId = PlaylistManager.createID(sNewName, plfOld.getDirectory()); // create a new playlist (with own fio and sAbs) Playlist plfNew = new Playlist(sNewId, sNewName, plfOld.getDirectory()); // Transfer all properties (id and name) plfNew.setProperties(plfOld.getProperties()); plfNew.setProperty(Const.XML_ID, sNewId); // reset new id and name plfNew.setProperty(Const.XML_NAME, sNewName); // reset new id and name // check file name and extension if (plfNew.getName().lastIndexOf('.') != plfNew.getName().indexOf('.')// just // one // '.' || !(UtilSystem.getExtension(ioNew).equals(Const.EXT_PLAYLIST))) { // check // extension Messages.showErrorMessage(134); throw new JajukException(134); } // check if future file exists (under windows, file.exists // return true even with different case so we test file name is // different) if (!ioNew.getName().equalsIgnoreCase(plfOld.getName()) && ioNew.exists()) { throw new JajukException(134); } // try to rename file on disk try { boolean result = plfOld.getFIO().renameTo(ioNew); if (!result) { throw new IOException(); } } catch (Exception e) { throw new JajukException(134, e); } // OK, remove old file and register this new file removeItem(plfOld); registerItem(plfNew); return plfNew; } finally { lock.writeLock().unlock(); } } /* * (non-Javadoc) * * @see org.jajuk.base.Observer#update(org.jajuk.base.Event) */ @Override public void update(JajukEvent event) { JajukEvents subject = event.getSubject(); if (JajukEvents.FILE_NAME_CHANGED.equals(subject)) { lock.writeLock().lock(); try { Properties properties = event.getDetails(); File fNew = (File) properties.get(Const.DETAIL_NEW); File fileOld = (File) properties.get(Const.DETAIL_OLD); // search references in playlists ReadOnlyIterator<Playlist> it = getPlaylistsIterator(); while (it.hasNext()) { Playlist plf = it.next(); if (plf.isReady()) { // check only in mounted // playlists, note that we can't // change unmounted playlists try { if (plf.getFiles().contains(fileOld)) { plf.replaceFile(fileOld, fNew); } } catch (Exception e) { Log.error(17, e); } } } } finally { lock.writeLock().unlock(); } } } /* * (non-Javadoc) * * @see org.jajuk.events.Observer#getRegistrationKeys() */ @Override public Set<JajukEvents> getRegistrationKeys() { Set<JajukEvents> eventSubjectSet = new HashSet<JajukEvents>(); eventSubjectSet.add(JajukEvents.FILE_NAME_CHANGED); return eventSubjectSet; } /** * Gets the playlist by id. * * @param sID Item ID * * @return item */ public Playlist getPlaylistByID(String sID) { return (Playlist) getItemByID(sID); } /** * Gets the playlists. * * @return ordered playlists list */ @SuppressWarnings("unchecked") public List<Playlist> getPlaylists() { return (List<Playlist>) getItems(); } /** * Gets the playlists iterator. * * @return playlists iterator */ @SuppressWarnings("unchecked") public ReadOnlyIterator<Playlist> getPlaylistsIterator() { return new ReadOnlyIterator<Playlist>((Iterator<Playlist>) getItemsIterator()); } /** * Returns the first playlist with the given name. * * @param name The name of the Playlist to search * * @return The playlist if found, null otherwise. */ public Playlist getPlaylistByName(String name) { for (Playlist pl : getPlaylists()) { // if this is the correct playlist, return it if (pl.getName().equals(name)) { return pl; } } // none found return null; } }