/*
* JBoss, Home of Professional Open Source.
* Copyright 2010, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.server.deployment.scanner;
import java.nio.file.DirectoryStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* An extensible filter for VFS files. Three arrays are maintained for checking: a prefix, suffix, and match array. If
* the filename starts with any of the prefixes, ends with any of the suffixes, or exactly matches any of the matches,
* then the accepts method will return false.
* <p/>
* NOTE: the arrays *must* be sorted for the string matching to work, and suffixes use the 'reverseComparator'
*
* @author Scott.Stark@jboss.org
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
*/
class ExtensibleFilter implements DirectoryStream.Filter<Path> {
/**
* Compare the strings backwards. This assists in suffix comparisons.
*/
private static final Comparator<String> reverseComparator = new Comparator<String>() {
public int compare(String o1, String o2) {
int idx1 = o1.length();
int idx2 = o2.length();
int comp = 0;
while (comp == 0 && idx1 > 0 && idx2 > 0)
comp = o1.charAt(--idx1) - o2.charAt(--idx2);
return (comp == 0) ? (idx1 - idx2) : comp;
}
};
/**
* the default prefix list
*/
private static final String[] DEFAULT_PREFIXES =
{ "#", "%", ",", ".", "_$" };
/**
* the default suffix list
*/
private static final String[] DEFAULT_SUFFIXES =
{ "#", "$", "%", "~", ",v", ".BAK", ".bak", ".old", ".orig", ".tmp", ".rej", ".sh", ".txt" };
/**
* the default matches list
*/
private static final String[] DEFAULT_MATCHES =
{ ".make.state", ".nse_depinfo", "CVS", "CVS.admin", "RCS", "RCSLOG", "SCCS", "TAGS", "core", "tags" };
/**
* The list of disallowed suffixes, sorted using reverse values
*/
private final List<String> suffixes;
/**
* The sorted list of disallowed prefixes
*/
private final List<String> prefixes;
/**
* The sorted list of disallowed values
*/
private final List<String> matches;
/**
* Use the default values for suffixes, prefixes, and matches
*/
public ExtensibleFilter() {
this(DEFAULT_MATCHES, DEFAULT_PREFIXES, DEFAULT_SUFFIXES);
}
/**
* Create using a custom set of matches, prefixes, and suffixes. If any of these arrays are null, then the
* corresponding default will be substituted.
*
* @param matches the matches
* @param prefixes the prefixes
* @param suffixes the suffixes
*/
public ExtensibleFilter(String[] matches, String[] prefixes, String[] suffixes) {
if (matches == null) {
matches = DEFAULT_MATCHES;
}
Arrays.sort(matches);
this.matches = new ArrayList<>(Arrays.asList(matches));
if (prefixes == null) {
prefixes = DEFAULT_PREFIXES;
}
Arrays.sort(prefixes);
this.prefixes = new ArrayList<>(Arrays.asList(prefixes));
if (suffixes == null) {
suffixes = DEFAULT_SUFFIXES;
}
Arrays.sort(suffixes, reverseComparator);
this.suffixes = new ArrayList<>(Arrays.asList(suffixes));
}
public void addPrefix(String prefix) {
prefixes.add(prefix);
Collections.sort(prefixes);
}
public void addPrefixes(String[] prefixes) {
this.prefixes.addAll(Arrays.asList(prefixes));
Collections.sort(this.prefixes);
}
public void delPrefix(String prefix) {
prefixes.remove(prefix);
}
public void delPrefixes(String[] prefixes) {
this.prefixes.removeAll(Arrays.asList(prefixes));
Collections.sort(this.prefixes);
}
public void addSuffix(String suffix) {
suffixes.add(suffix);
Collections.sort(suffixes, reverseComparator);
}
public void addSuffixes(String[] suffixes) {
this.suffixes.addAll(Arrays.asList(suffixes));
Collections.sort(this.suffixes, reverseComparator);
}
public void delSuffix(String suffix) {
suffixes.remove(suffix);
}
public void delSuffixes(String[] suffixes) {
this.suffixes.removeAll(Arrays.asList(suffixes));
Collections.sort(this.suffixes, reverseComparator);
}
public String[] getSuffixes() {
String[] tmp = new String[suffixes.size()];
suffixes.toArray(tmp);
return tmp;
}
public void setSuffixes(String[] suffixes) {
Arrays.sort(suffixes, reverseComparator);
this.suffixes.clear();
this.suffixes.addAll(Arrays.asList(suffixes));
}
public String[] getPrefixes() {
String[] tmp = new String[prefixes.size()];
prefixes.toArray(tmp);
return tmp;
}
public void setPrefixes(String[] prefixes) {
Arrays.sort(prefixes);
this.prefixes.clear();
this.prefixes.addAll(Arrays.asList(prefixes));
}
public String[] getMatches() {
String[] tmp = new String[matches.size()];
matches.toArray(tmp);
return tmp;
}
public void setMatches(String[] matches) {
Arrays.sort(matches);
this.matches.clear();
this.matches.addAll(Arrays.asList(matches));
}
/**
* If the filename matches any string in the prefix, suffix, or matches array, return false. Perhaps a bit of
* overkill, but this method operates in log(n) time, where n is the size of the arrays.
*
* @param file The file to be tested
*
* @return <code>false</code> if the filename matches any of the prefixes, suffixes, or matches.
*/
@Override
public boolean accept(Path file) {
String name = file.getFileName().toString();
// check exact match
int index = Collections.binarySearch(matches, name);
if (index >= 0) {
return false;
}
// check prefix
index = Collections.binarySearch(prefixes, name);
if (index >= 0) {
return false;
}
if (index < -1) {
// The < 0 index gives the first index greater than name
int firstLessIndex = -2 - index;
String prefix = prefixes.get(firstLessIndex);
// If name starts with an ignored prefix ignore name
if (name.startsWith(prefix)) {
return false;
}
}
// check suffix
index = Collections.binarySearch(suffixes, name, reverseComparator);
if (index >= 0) {
return false;
}
if (index < -1) {
// The < 0 index gives the first index greater than name
int firstLessIndex = -2 - index;
String suffix = suffixes.get(firstLessIndex);
// If name ends with an ignored suffix ignore name
if (name.endsWith(suffix)) {
return false;
}
}
// everything checks out.
return true;
}
}