ijfx.core.imagedb.DefaultExplorerService.java Source code

Java tutorial

Introduction

Here is the source code for ijfx.core.imagedb.DefaultExplorerService.java

Source

/*
This file is part of ImageJ FX.
    
ImageJ FX 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.
    
ImageJ FX 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 ImageJ FX.  If not, see <http://www.gnu.org/licenses/>. 
    
 Copyright 2015,2016 Cyril MONGIS, Michael Knop
       
 */
package ijfx.core.imagedb;

import com.google.common.collect.Lists;
import ijfx.core.hash.HashService;
import ijfx.core.metadata.MetaDataService;
import ijfx.core.metadata.MetaDataSet;
import ijfx.core.notification.NotificationService;
import ijfx.core.prefs.JsonPreferenceService;
import ijfx.ui.main.ImageJFX;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import mongis.utils.TextFileUtils;
import mongis.utils.task.ProgressHandler;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.CanReadFileFilter;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.OrFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.scijava.Context;
import org.scijava.Priority;
import org.scijava.app.StatusService;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.service.AbstractService;
import org.scijava.service.Service;
import rx.subjects.PublishSubject;

/**
 *
 * @author Cyril MONGIS, 2016
 */
@Plugin(type = Service.class, priority = Priority.VERY_LOW_PRIORITY)
public class DefaultExplorerService extends AbstractService implements ExplorerService {

    private Executor executor = Executors.newFixedThreadPool(1);

    private HashMap<File, DefaultImageRecord> recordMap;

    private Queue<File> fileQueue = new LinkedList<>();

    @Parameter
    private MetaDataService metadataExtractorService;

    @Parameter
    private JsonPreferenceService jsonPreferenceService;

    private final static Logger logger = ImageJFX.getLogger();

    @Parameter
    private NotificationService notificationService;

    @Parameter
    private StatusService statusService;

    private static String FILE_ADDED = "%s images where analyzed.";

    private final PublishSubject<ImageRecord> saveQueue = PublishSubject.create();

    @Override
    public void initialize() {
        super.initialize();

        saveQueue.observeOn(ImageJFX.getPublishSubjectScheduler())
                .filter(imageRecord -> getRecordMap().containsValue(imageRecord) == false)
                .buffer(10, TimeUnit.SECONDS).filter(list -> list.isEmpty() == false).subscribe(list -> save());

    }

    @Override
    public boolean isPresent(File file) {
        return getRecordMap().containsKey(file);
    }

    private Map<File, DefaultImageRecord> getRecordMap() {
        if (recordMap == null) {
            recordMap = new HashMap<>();
            load().forEach(record -> recordMap.put(record.getFile(), record));
        }
        return recordMap;
    }

    @Override
    public void addRecord(ImageRecord imageRecord) {
        getRecordMap().put(imageRecord.getFile(), (DefaultImageRecord) imageRecord);
        saveQueue.onNext(imageRecord);
    }

    @Override
    public ImageRecord addRecord(File file, MetaDataSet metaDataSet) {
        ImageRecord record = new DefaultImageRecord(file, metaDataSet);
        addRecord(record);
        return record;
    }

    @Override
    public Collection<? extends ImageRecord> getRecords() {
        return getRecordMap().values();
    }

    @Override
    public Collection<? extends ImageRecord> queryRecords(Predicate<ImageRecord> query) {
        return getRecordMap().values().parallelStream().filter(query).collect(Collectors.toList());
    }

    public ImageRecord getRecord(File file) {

        ImageRecord imageRecord;
        if (getRecordMap().containsKey(file) == false) {
            imageRecord = new DefaultImageRecord(file, metadataExtractorService.extractMetaData(file));
            if (imageRecord.getMetaDataSet().size() == 0) {
                throw new IllegalArgumentException("Error when reading file metadata : " + file.getName());
            }
            addRecord(imageRecord);
        } else {
            imageRecord = getRecordMap().get(file);
        }

        return imageRecord;
    }

    private void save() {
        jsonPreferenceService.savePreference(getRecords(), JSON_FILE);
    }

    private List<DefaultImageRecord> load() {
        return jsonPreferenceService.loadListFromJson(JSON_FILE, DefaultImageRecord.class);
    }

    @Override
    public synchronized Collection<? extends ImageRecord> getRecordsFromDirectory(ProgressHandler handler,
            File directory) {

        List<ImageRecord> records = new ArrayList<>();

        statusService.showStatus(1, 10, "Analyzing folder : " + directory.getName());
        Collection<File> files = getAllImagesFromDirectory(directory);
        int count = 0;
        int total = files.size();

        handler.setTotal(total);

        List<ImageRecord> collect = files.stream().map(f -> {
            handler.increment(1.0);
            try {
                return getRecord(f);
            } catch (Exception e) {
                return null;
            }
        }).filter(record -> record != null).collect(Collectors.toList());

        return collect;

    }

    public void forceSave() {
        ImageJFX.getThreadPool().execute(this::save);
    }

    @Parameter
    private Context context;
    @Parameter
    private HashService hashService;

    private final String FORMAT_FILE_NAME = "/supportedFormats.txt";
    public List<String> formats = new ArrayList<>();

    @Override
    public IOFileFilter getIOFileFilter() {
        List<IOFileFilter> suffixFilters = new ArrayList<>();
        for (String ext : getSupportedExtensions()) {

            suffixFilters.add(new SuffixFileFilter(ext));
        }
        IOFileFilter suffixFilter = new OrFileFilter(suffixFilters);
        return suffixFilter;
    }

    public static IOFileFilter canReadFilter(IOFileFilter filter) {
        return new AndFileFilter(filter, CanReadFileFilter.CAN_READ);
    }

    public static IOFileFilter getDirectoryFilter() {
        return DirectoryFileFilter.INSTANCE;
    }

    @Override
    public String[] getSupportedExtensions() {
        if (formats.isEmpty()) {
            loadFormats();
        }
        int size = formats.size();
        String[] extensions = new String[size];
        for (int i = 0; i < size; i++) {
            String filterExt = formats.get(i);
            extensions[i] = filterExt.substring(2, filterExt.length());
        }
        return extensions;
    }

    private void loadFormats() {
        try {
            formats.clear();
            String formatsFromFile = TextFileUtils.readFileFromJar(ImageJFX.class, FORMAT_FILE_NAME);

            String[] lines = formatsFromFile.split("\n");
            for (String ext : lines) {
                formats.add("*" + ext);
            }
        } catch (IOException ex) {
            ImageJFX.getLogger().log(Level.SEVERE,
                    "Error when loading the file containing all the possible formats.", ex);
        }
    }

    @Override
    public Collection<File> getAllImagesFromDirectory(File file) {
        if (file.isDirectory() == false) {
            return Lists.newArrayList(file);
        }
        return FileUtils.listFiles(file, getSupportedExtensions(), true);
    }

    @Override
    public Collection<File> getAllImagesFromDirectory(File file, boolean recursive) {
        if (recursive) {
            return getAllImagesFromDirectory(file);
        } else {
            final IOFileFilter filter = getIOFileFilter();
            return Stream.of(file.listFiles()).filter(filter::accept).collect(Collectors.toList());

        }
    }

}