/** * Walks through all directories and removes the ones for this device. * * @param dirsToRefresh list of the directory to refresh, null if all of them * @return true if there was any directory removed */ private boolean cleanDirectories(List<Directory> dirsToRefresh) { boolean bChanges = false; List<Directory> dirs = null; if (dirsToRefresh == null) { dirs = DirectoryManager.getInstance().getDirectories(); } else { // If one or more named directories are provided, not only clean them up but also their sub // directories dirs = new ArrayList<Directory>(dirsToRefresh); for (Directory dir : dirsToRefresh) { dirs.addAll(dir.getDirectoriesRecursively()); } } for (final Directory dir : dirs) { if (!ExitService.isExiting() && dir.getDevice().equals(this) && dir.getDevice().isMounted() && !dir.getFio().exists()) { // note that associated files are removed too DirectoryManager.getInstance().removeDirectory(dir.getID()); Log.debug("Removed: " + dir); bChanges = true; } } return bChanges; }
/** * Walk through tall Files and remove the ones for the current device. * * @param dirsToRefresh list of the directory to refresh, null if all of them * @return true if there was any file removed. */ private boolean cleanFiles(List<Directory> dirsToRefresh) { boolean bChanges = false; final List<org.jajuk.base.File> files = FileManager.getInstance().getFiles(); for (final org.jajuk.base.File file : files) { // check if it is a file located inside refreshed directory if (dirsToRefresh != null) { boolean checkIt = false; for (Directory directory : dirsToRefresh) { if (file.hasAncestor(directory)) { checkIt = true; } } // This item is not in given directories, just continue if (!checkIt) { continue; } } if (!ExitService.isExiting() && file.getDirectory().getDevice().equals(this) && file.isReady() && // Remove file if it doesn't exist any more or if it is a iTunes // file (useful for jajuk < 1.4) (!file.getFIO().exists() || file.getName().startsWith("._"))) { FileManager.getInstance().removeFile(file); Log.debug("Removed: " + file); bChanges = true; if (reporter != null) { reporter.notifyFileOrPlaylistDropped(); } } } return bChanges; }
/** * Walk through all Playlists and remove the ones for the current device. * * @param dirsToRefresh list of the directory to refresh, null if all of them * @return true if there was any playlist removed */ private boolean cleanPlaylist(List<Directory> dirsToRefresh) { boolean bChanges = false; final List<Playlist> plfiles = PlaylistManager.getInstance().getPlaylists(); for (final Playlist plf : plfiles) { // check if it is a playlist located inside refreshed directory if (dirsToRefresh != null) { boolean checkIt = false; for (Directory directory : dirsToRefresh) { if (plf.hasAncestor(directory)) { checkIt = true; } } // This item is not in given directories, just continue if (!checkIt) { continue; } } if (!ExitService.isExiting() && plf.getDirectory().getDevice().equals(this) && plf.isReady() && !plf.getFIO().exists()) { PlaylistManager.getInstance().removeItem(plf); Log.debug("Removed: " + plf); if (reporter != null) { reporter.notifyFileOrPlaylistDropped(); } bChanges = true; } } return bChanges; }
/** * Scan recursively. * * @param dir top directory to scan * @param bDeepScan whether we want to perform a deep scan (read tags again) */ private void scanRecursively(final Directory dir, final boolean bDeepScan) { dir.scan(bDeepScan, reporter); if (reporter != null) { reporter.updateState(dir); } final File[] files = dir.getFio().listFiles(UtilSystem.getDirFilter()); if (files != null) { for (final File element : files) { // Leave ASAP if exit request if (ExitService.isExiting()) { return; } final Directory subDir = DirectoryManager.getInstance().registerDirectory(element.getName(), dir, this); scanRecursively(subDir, bDeepScan); } } }
/** * The refresh itself. * * @param bDeepScan whether it is a deep refresh request or only fast * @param bManual whether it is a manual refresh or auto * @param dirsToRefresh list of the directory to refresh, null if all of them * @return true if some changes occurred in device */ boolean refreshCommand( final boolean bDeepScan, final boolean bManual, List<Directory> dirsToRefresh) { try { // Check if this device is mounted (useful when called by // automatic refresh) if (!isMounted()) { return false; } // Check that device is still available boolean readyToMount = checkDevice(); if (!readyToMount) { return false; } bAlreadyRefreshing = true; // reporter is already set in case of manual refresh if (reporter == null) { reporter = new RefreshReporter(this); } // Notify the reporter of the actual refresh startup reporter.refreshStarted(); lDateLastRefresh = System.currentTimeMillis(); // check Jajuk is not exiting because a refresh cannot start in // this state if (ExitService.isExiting()) { return false; } int iNbFilesBeforeRefresh = FileManager.getInstance().getElementCount(); int iNbDirsBeforeRefresh = DirectoryManager.getInstance().getElementCount(); int iNbPlaylistsBeforeRefresh = PlaylistManager.getInstance().getElementCount(); if (bDeepScan && Log.isDebugEnabled()) { Log.debug("Starting refresh of device : " + this); } // Create a directory for device itself and scan files to allow // files at the root of the device final Directory top = DirectoryManager.getInstance().registerDirectory(this); if (!getDirectories().contains(top)) { addDirectory(top); } // Start actual scan List<Directory> dirs = null; if (dirsToRefresh == null) { // No directory specified ? refresh the top directory dirs = new ArrayList<Directory>(1); dirs.add(top); } else { dirs = dirsToRefresh; } for (Directory dir : dirs) { scanRecursively(dir, bDeepScan); } // Force a GUI refresh if new files or directories discovered or have been // removed if (((FileManager.getInstance().getElementCount() - iNbFilesBeforeRefresh) != 0) || ((DirectoryManager.getInstance().getElementCount() - iNbDirsBeforeRefresh) != 0) || ((PlaylistManager.getInstance().getElementCount() - iNbPlaylistsBeforeRefresh) != 0)) { return true; } return false; } catch (final Exception e) { // and regular ones logged Log.error(e); return false; } finally { // make sure to unlock refreshing even if an error occurred bAlreadyRefreshing = false; // reporter is null if mount is not mounted due to early return if (reporter != null) { // Notify the reporter of the actual refresh startup reporter.done(); // Reset the reporter as next time, it could be another type reporter = null; } } }
/** * Synchronize a device with another one (unidirectional). * * @param dSrc * @param dest * @return nb of created files */ private int synchronizeUnidirectonal(final Device dSrc, final Device dest) { final Set<Directory> hsSourceDirs = new HashSet<Directory>(100); // contains paths ( relative to device) of desynchronized dirs final Set<String> hsDesynchroPaths = new HashSet<String>(10); final Set<Directory> hsDestDirs = new HashSet<Directory>(100); int iNbCreatedFiles = 0; List<Directory> dirs = DirectoryManager.getInstance().getDirectories(); for (Directory dir : dirs) { if (dir.getDevice().equals(dSrc)) { // don't take desynchronized dirs into account if (dir.getBooleanValue(Const.XML_DIRECTORY_SYNCHRONIZED)) { hsSourceDirs.add(dir); } else { hsDesynchroPaths.add(dir.getRelativePath()); } } } for (Directory dir : dirs) { if (dir.getDevice().equals(dest)) { if (dir.getBooleanValue(Const.XML_DIRECTORY_SYNCHRONIZED)) { // don't take desynchronized dirs into account hsDestDirs.add(dir); } else { hsDesynchroPaths.add(dir.getRelativePath()); } } } // handle known extensions and image files final FileFilter filter = new JajukFileFilter( false, new JajukFileFilter[] {KnownTypeFilter.getInstance(), ImageFilter.getInstance()}); for (Directory dir : hsSourceDirs) { // give a chance to exit during sync if (ExitService.isExiting()) { return iNbCreatedFiles; } boolean bNeedCreate = true; final String sPath = dir.getRelativePath(); // check the directory on source is not desynchronized. If it // is, leave without checking files if (hsDesynchroPaths.contains(sPath)) { continue; } for (Directory dir2 : hsDestDirs) { if (dir2.getRelativePath().equals(sPath)) { // directory already exists on this device bNeedCreate = false; break; } } // create it if needed final File fileNewDir = new File(new StringBuilder(dest.getUrl()).append(sPath).toString()); if (bNeedCreate && !fileNewDir.mkdirs()) { Log.warn("Could not create directory " + fileNewDir); } // synchronize files final File fileSrc = new File(new StringBuilder(dSrc.getUrl()).append(sPath).toString()); final File[] fSrcFiles = fileSrc.listFiles(filter); if (fSrcFiles != null) { for (final File element : fSrcFiles) { File[] filesArray = fileNewDir.listFiles(filter); if (filesArray == null) { // fileNewDir is not a directory or an error occurred ( // read/write right ? ) continue; } final List<File> files = Arrays.asList(filesArray); // Sort so files are copied in the filesystem order Collections.sort(files); boolean bNeedCopy = true; for (final File element2 : files) { if (element.getName().equalsIgnoreCase(element2.getName())) { bNeedCopy = false; } } if (bNeedCopy) { try { UtilSystem.copyToDir(element, fileNewDir); iNbCreatedFiles++; lVolume += element.length(); InformationJPanel.getInstance() .setMessage( new StringBuilder(Messages.getString("Device.41")) .append(dSrc.getName()) .append(',') .append(dest.getName()) .append(Messages.getString("Device.42")) .append(element.getAbsolutePath()) .append("]") .toString(), InformationJPanel.MessageType.INFORMATIVE); } catch (final JajukException je) { Messages.showErrorMessage(je.getCode(), element.getAbsolutePath()); Messages.showErrorMessage(27); Log.error(je); return iNbCreatedFiles; } catch (final Exception e) { Messages.showErrorMessage(20, element.getAbsolutePath()); Messages.showErrorMessage(27); Log.error(20, "{{" + element.getAbsolutePath() + "}}", e); return iNbCreatedFiles; } } } } } return iNbCreatedFiles; }