001    /**
002     * 
003     */
004    package org.wdssii.core.fam;
005    
006    import java.io.File;
007    import java.io.FilenameFilter;
008    import java.util.Arrays;
009    import java.util.Date;
010    import java.util.HashSet;
011    import java.util.Set;
012    
013    import org.apache.commons.logging.Log;
014    import org.apache.commons.logging.LogFactory;
015    
016    /**
017     * @author lakshman
018     * 
019     */
020    public class FamIndexHelperLsImpl implements FamIndexHelper {
021            private String indexDir;
022            private Set<String> knownFiles;
023            private long timeOfLastUpdate;
024            private final FilenameFilter filenamePattern;
025            private NewFilesOnly newFilesOnly;
026            
027            private long updateIntervalInMilliSeconds = 60 * 1000; // milliseconds
028            private final File[] emptyList = new File[0];
029            private final Log log = LogFactory.getLog(FamIndexHelperLsImpl.class);
030    
031            public FamIndexHelperLsImpl(FilenameFilter pattern){
032                    this.filenamePattern = pattern;
033            }
034            
035            /** By default look only at files that end with .fml */
036            public FamIndexHelperLsImpl(){
037                    this(new FmlFilesOnlyFilter());
038            }
039            
040            @Override
041            public File[] getInitialFiles(String indexDir) {
042                    this.close(); // resets
043                    this.indexDir = indexDir;
044                    File[] files = new File(indexDir).listFiles(filenamePattern);
045                    return processFileListAndReturn(files);
046            }
047            
048            @Override
049            public void close(){
050                    knownFiles = new HashSet<String>();
051                    timeOfLastUpdate = 0;
052                    newFilesOnly = new NewFilesOnly();
053            }
054    
055            private File[] processFileListAndReturn(File[] files) {
056                    if (files == null) {
057                            log.warn("Problem listing files in " + indexDir);
058                            return emptyList;
059                    }
060    
061                    if (log.isDebugEnabled()) {
062                            log.debug("Found " + files.length + " files in " + indexDir);
063                    }
064    
065                    Arrays.sort(files); // alphabetical
066                    for (File f : files) {
067                            knownFiles.add(f.getAbsolutePath());
068                    }
069                    return files;
070            }
071    
072            /** Accepts only new FML files */
073            public class NewFilesOnly implements FilenameFilter {
074                    @Override
075                    public boolean accept(File dir, String baseName) {
076                            boolean isFml = filenamePattern.accept(dir, baseName);
077                            if (isFml) {
078                                    File f = new File(dir, baseName);
079                                    if (isNew(f)) {
080                                            return true;
081                                    }
082                            }
083                            return false;
084                    }
085    
086                    protected boolean isNew(File f) {
087                            String absPath = f.getAbsolutePath();
088    
089                            // Has this file been aged off in memory?
090                            if (!knownFiles.isEmpty()) {
091                                    String firstFile = knownFiles.iterator().next();
092                                    if (absPath.compareTo(firstFile) < 0) {
093                                            // older than oldest file in map
094                                            return false;
095                                    }
096                            }
097                            return (!knownFiles.contains(absPath));
098                    }
099            }
100    
101            @Override
102            public File[] getNewFiles() {
103                    // don't update if we just did
104                    long now = new Date().getTime();
105                    if ((now - timeOfLastUpdate) < updateIntervalInMilliSeconds) {
106                            return emptyList;
107                    }
108                    timeOfLastUpdate = now;
109    
110                    // get all files
111                    File[] files = new File(indexDir).listFiles(newFilesOnly);
112                    return processFileListAndReturn(files);
113            }
114            
115            @Override
116            public void pruneToMaxSize(long maxNumRecords, long targetNumRecords){
117                    // prune
118                    if (knownFiles.size() > maxNumRecords){
119                            String[] temp = knownFiles.toArray(new String[0]);
120                            knownFiles.clear();
121                            for (int i=1; i <= targetNumRecords; ++i){
122                                    knownFiles.add(temp[temp.length-i]);
123                            }
124                    }
125            }
126    }