/* * Copyright 2012, CMM, University of Queensland. * * This file is part of Paul. * * Paul 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 3 of the License, or * (at your option) any later version. * * Paul 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 Paul. If not, see <http://www.gnu.org/licenses/>. */ package au.edu.uq.cmm.paul.grabber; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import au.edu.uq.cmm.paul.DatafileTemplateConfig; import au.edu.uq.cmm.paul.Paul; import au.edu.uq.cmm.paul.status.Facility; import au.edu.uq.cmm.paul.watcher.FileWatcherEvent; import au.edu.uq.cmm.paul.watcher.FileWatcherEventListener; /** * This is the base class for the FileGrabber service, and the special grabber * that we use when figuring out what could potentially be grabbed. * * @author scrawley */ public abstract class AbstractFileGrabber implements FileWatcherEventListener { static final Logger LOG = LoggerFactory.getLogger(AbstractFileGrabber.class); static final int DEFAULT_FILE_SETTLING_TIME = 2000; // 2 seconds private final HashMap<File, WorkEntry> workMap = new HashMap<File, WorkEntry>(); private final Facility facility; private final Paul services; public AbstractFileGrabber(Paul services, Facility facility) { this.services = services; this.facility = facility; } public final synchronized void remove(File file) { LOG.debug("Removing workMap entry for " + file); workMap.remove(file); } public final synchronized void reorderQueue(BlockingQueue<Runnable> queue) { LOG.info("Reordering a FileGrabber work queue (contains " + queue.size() + " potential datasets)"); List<Runnable> workList = new ArrayList<Runnable>(queue.size()); queue.drainTo(workList); Collections.sort(workList, new Comparator<Runnable>() { @Override public int compare(Runnable o1, Runnable o2) { WorkEntry w1 = (WorkEntry) o1; WorkEntry w2 = (WorkEntry) o2; return Long.compare(w1.getLatestFileTimestamp(), w2.getLatestFileTimestamp()); } }); queue.addAll(workList); } public final synchronized int analyseTree(File directory, long after, long before) { File[] list = directory.listFiles(); if (list == null) { LOG.debug("Cannot get a file list for '" + directory + "': permissions problem?"); return 0; } int count = 0; for (File member : list) { long lastModified; if (member.isDirectory()) { count += analyseTree(member, after, before); } else if (member.isFile() && (lastModified = member.lastModified()) > after && lastModified < before) { FileWatcherEvent event = new FileWatcherEvent( facility, member, true, lastModified, true); processEvent(event); count++; } } return count; } @Override public final void eventOccurred(FileWatcherEvent event) { processEvent(event); } private void processEvent(FileWatcherEvent event) { File file = event.getFile(); Facility facility = (Facility) event.getFacility(); LOG.debug("FileWatcherEvent received : " + facility.getFacilityName() + "," + file + "," + event.isCreate()); File baseFile = null; for (DatafileTemplateConfig datafile : facility.getDatafileTemplates()) { Pattern pattern = Pattern.compile(datafile.getFilePattern()); Matcher matcher = pattern.matcher(file.getAbsolutePath()); if (matcher.matches()) { baseFile = new File(matcher.group(1)); break; } } if (baseFile != null) { synchronized (this) { // If we are shutting down, we only deal with events for // files in datasets we've already started grabbing. if (!isShutDown()) { WorkEntry workEntry = workMap.get(baseFile); if (workEntry == null) { workEntry = new WorkEntry(services, event, baseFile); workMap.put(baseFile, workEntry); enqueueWorkEntry(workEntry); LOG.debug("Added a workEntry"); } else { workEntry.addEvent(event); } } } } else { LOG.debug("FileWatcherEvent doesn't match any template : " + facility.getFacilityName() + "," + file + "," + event.isCreate()); } } protected abstract boolean isShutDown(); protected abstract void enqueueWorkEntry(WorkEntry entry); protected final Facility getFacility() { return facility; } protected final Paul getServices() { return services; } }