All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openidex.search.SimpleSearchIterator Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.openidex.search;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataFolder;

/**
 *
 * @author  Marian Petras
 */
class SimpleSearchIterator implements Iterator {

    /** current enumeration of children */
    private Enumeration childrenEnum;
    /**
     * filters to be applied on the current enumeration of children
     * ({@link #childrenEnum})
     */
    private List filters;
    /**
     * contains either an equal copy of {@link #filters} or null
     */
    private List filtersCopy;
    /** */
    private final boolean recursive;
    /** */
    private boolean searchInArchives = false; // TODO make configurable
    /** stack of the ancestor folders' children enumerations */
    private final List> enums
            = new ArrayList>();            //unsynced stack
    /**
     * stack of filter lists to be applied on children of the ancestor folders
     * ({@link #enums})
     */
    private final List> filterLists
            = new ArrayList>();      //unsynced stack
    /** whether value of {@link #nextObject} is up-to-date */
    private boolean upToDate = false;
    /**
     * DataObject to be returned the next time method
     * {@link #next()} is called
     */
    private FileObject nextObject;

    /**
     */
    SimpleSearchIterator(DataFolder folder,
                         boolean recursive,
                         List filters) {
        this.childrenEnum = folder.getPrimaryFile().getChildren(false);
        this.recursive = recursive;
        this.filters = (filters != null) ? new ArrayList(filters)
                                         : null;
    }

    /**
     */
    public boolean hasNext() {
        if (!upToDate) {
            update();
        }
        return nextObject != null;
    }

    /** 
     */
    public FileObject next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }

        upToDate = false;
        return nextObject;
    }

    /**
     */
    private void update() {
        assert upToDate == false;
        assert childrenEnum != null;
        do {
            if (childrenEnum.hasMoreElements()) {
                FileObject file = childrenEnum.nextElement();
                if (file.isFolder()) {
                    if (recursive) {
                        processFolder(file);
                    }
                } else {
                    if (FileUtil.isArchiveFile(file)
                            && recursive && searchInArchives) {
                        processFolder(FileUtil.getArchiveRoot(file));
                    }
                    if ((filters == null) || checkFileFilters(file)) {
                        nextObject = file;
                        break;
                    }
                }
            } else {
                assert enums.isEmpty() == filterLists.isEmpty();
                
                nextObject = null;
                
                if (enums.isEmpty()) {
                    childrenEnum = null;
                    continue;
                }
                
                /* pop an element from the stack of children enumerations: */
                childrenEnum = enums.remove(enums.size() - 1);
                
                /* pop an element from the stack of FileObjectFilters: */
                filters = filterLists.remove(filterLists.size() - 1);
                if ((filtersCopy != null)
                        && (filtersCopy.size() != filters.size())) {
                    filtersCopy = null;
                }
            }
        } while (childrenEnum != null);
        
        upToDate = true;
    }
    
    private void processFolder(FileObject folder) {
        
        if (filters != null) {
            final List subfolderFilters = 
                    checkFolderFilters(folder);
            if (subfolderFilters == null) {
                return;
            }
            filterLists.add(filters);
            if (subfolderFilters.size() != filters.size()) {
                filters = (!subfolderFilters.isEmpty())
                        ? subfolderFilters
                        : null;
            }
        } else {
            filterLists.add(null);
        }
        enums.add(childrenEnum);
        childrenEnum = folder.getChildren(false);
    }

    /**
     * Computes a list of filters to be applied on the folder's children.
     * The current list of filters is used as a base and then each filter
     * is checked with the folder as a parameter.
     * 

* If any of the filters returns DO_NOT_TRAVERSE, * the method returns null and no further filters * are checked. * If a filter returns TRAVERSE_ALL_SUBFOLDERS, * the filter is removed from the base as it needs not be applied * on the folder's children. The remaining list of filters is returned * as a result. * * @param folder folder to compute children filters for * @return list of filters to be applied on the folder's children; * or null if the folder should not be traversed */ private List checkFolderFilters(final FileObject folder) { assert folder.isFolder(); assert filters != null; if (filtersCopy == null) { filtersCopy = new ArrayList(filters); } List result = filtersCopy; cycle: for (Iterator i = result.iterator(); i.hasNext(); ) { FileObjectFilter filter = i.next(); final int traverseCommand = filter.traverseFolder(folder); switch (traverseCommand) { case FileObjectFilter.TRAVERSE: break; case FileObjectFilter.DO_NOT_TRAVERSE: result = null; break cycle; case FileObjectFilter.TRAVERSE_ALL_SUBFOLDERS: i.remove(); filtersCopy = null; break; default: assert false; break; } } return result; } /** * Checks whether the file passes all of the current * {@link #filters}. * * @param file file to be checked * @return true if the file passed all of the filters, * false otherwise */ private boolean checkFileFilters(FileObject file) { assert file.isFolder() == false; assert filters != null; for (FileObjectFilter filter : filters) { if (!filter.searchFile(file)) { return false; } } return true; } /** */ public void remove() { throw new UnsupportedOperationException(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy