/* * 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.apache.tools.ant.filters; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.types.Parameter; /** *
* Sort a file before and/or after the file. *
* ** Examples: *
* ** <copy todir="build"> * <fileset dir="input" includes="*.txt"/> * <filterchain> * <sortfilter/> * </filterchain> * </copy> ** *
* Sort all files *.txt
from src location and copy
* them into build location. The lines of each file are sorted
* in ascendant order comparing the lines via the
* String.compareTo(Object o)
method.
*
* <copy todir="build"> * <fileset dir="input" includes="*.txt"/> * <filterchain> * <sortfilter reverse="true"/> * </filterchain> * </copy> ** *
* Sort all files *.txt
from src location into reverse
* order and copy them into build location. If reverse parameter has
* value true
(default value), then the output line of the files
* will be in ascendant order.
*
* <copy todir="build"> * <fileset dir="input" includes="*.txt"/> * <filterchain> * <filterreader classname="org.apache.tools.ant.filters.SortFilter"> * <param name="comparator" value="org.apache.tools.ant.filters.EvenFirstCmp"/> * </filterreader> * </filterchain> * </copy> ** *
* Sort all files *.txt
from src location using as
* sorting criterium EvenFirstCmp
class, that sorts the file
* lines putting even lines first then odd lines for example. The modified files
* are copied into build location. The EvenFirstCmp
,
* has to an instanciable class via Class.newInstance()
,
* therefore in case of inner class has to be static. It also has to
* implement java.util.Comparator
interface, for example:
*
* package org.apache.tools.ant.filters; * ...(omitted) * public final class EvenFirstCmp implements <b>Comparator</b> { * public int compare(Object o1, Object o2) { * ...(omitted) * } * } ** *
The example above is equivalent to:
* ** ** <componentdef name="evenfirst" * classname="org.apache.tools.ant.filters.EvenFirstCmp"/> * <copy todir="build"> * <fileset dir="input" includes="*.txt"/> * <filterchain> * <sortfilter> * <evenfirst/> * </sortfilter> * </filterchain> * </copy> *
If parameter comparator
is present, then
* reverse
parameter will not be taken into account.
java.util.Comparator
interface.
*/
private static final String COMPARATOR_KEY = "comparator";
/**
* Instance of comparator class to be used for sorting.
*/
private Comparator super String> comparator = null;
/**
* Controls if the sorting process will be in ascendant/descendant order. If
* If has value true
, then the line of the file will be
* sorted on descendant order. Default value: false
. It will
* be considered only if comparator
is null
.
*/
private boolean reverse;
/**
* Stores the lines to be sorted.
*/
private Listnull
if the
* next call to read()
should read the original stream to
* find the next matching line.
*/
private String line = null;
private Iteratornull
.
*/
public SortFilter(final Reader in) {
super(in);
}
/**
* Returns the next character in the filtered stream. If the desired number
* of lines have already been read, the resulting stream is effectively at
* an end. Otherwise, the next character from the underlying stream is read
* and returned.
*
* @return the next character in the resulting stream, or -1 if the end of
* the resulting stream has been reached
*
* @exception IOException
* if the underlying stream throws an IOException during
* reading
*/
public int read() throws IOException {
if (!getInitialized()) {
initialize();
setInitialized(true);
}
int ch = -1;
if (line != null) {
/*
* We are on the state: "reading the current line", lines are
* already sorted
*/
ch = line.charAt(0);
if (line.length() == 1) {
line = null;
} else {
line = line.substring(1);
}
} else {
if (lines == null) {
// We read all lines and sort them
lines = new ArrayListnull
.
*
* @return a new filter based on this configuration, but filtering the
* specified reader
*/
public Reader chain(final Reader rdr) {
SortFilter newFilter = new SortFilter(rdr);
newFilter.setReverse(isReverse());
newFilter.setComparator(getComparator());
newFilter.setInitialized(true);
return newFilter;
}
/**
* Returns true
if the sorting process will be in reverse
* order, otherwise the sorting process will be in ascendant order.
*
* @return true
if the sorting process will be in reverse
* order, otherwise the sorting process will be in ascendant order.
*/
public boolean isReverse() {
return reverse;
}
/**
* Sets the sorting process will be in ascendant (reverse=false
)
* or to descendant (reverse=true
).
*
* @param reverse
* Boolean representing reverse ordering process.
*/
public void setReverse(boolean reverse) {
this.reverse = reverse;
}
/**
* Returns the comparator to be used for sorting.
*
* @return the comparator
*/
public Comparator super String> getComparator() {
return comparator;
}
/**
* Set the comparator to be used as sorting criterium.
*
* @param comparator
* the comparator to set
*/
public void setComparator(Comparator super String> comparator) {
this.comparator = comparator;
}
/**
* Set the comparator to be used as sorting criterion as nested element.
*
* @param comparator
* the comparator to set
*/
public void add(Comparator super String> comparator) {
if (this.comparator != null && comparator != null) {
throw new BuildException("can't have more than one comparator");
}
setComparator(comparator);
}
/**
* Scans the parameters list
*/
private void initialize() throws IOException {
// get parameters
Parameter[] params = getParameters();
if (params != null) {
for (int i = 0; i < params.length; i++) {
final String paramName = params[i].getName();
if (REVERSE_KEY.equals(paramName)) {
setReverse(Boolean.valueOf(params[i].getValue())
.booleanValue());
continue;
}
if (COMPARATOR_KEY.equals(paramName)) {
try {
String className = (String) params[i].getValue();
@SuppressWarnings("unchecked")
final Comparator super String> comparatorInstance = (Comparator super String>) (Class
.forName(className).newInstance());
setComparator(comparatorInstance);
continue;
} catch (InstantiationException e) {
throw new BuildException(e);
} catch (IllegalAccessException e) {
/*
* Probably a inner non-static class, this this case is
* not considered
*/
throw new BuildException(e);
} catch (ClassNotFoundException e) {
throw new BuildException(e);
} catch (ClassCastException e) {
throw new BuildException("Value of comparator attribute"
+ " should implement"
+ " java.util.Comparator"
+ " interface");
} catch (Exception e) {
throw new BuildException(e);
}
}
}
}
}
/**
* Sorts the read lines (lines
) according to the sorting
* criteria defined by the user.
*
*/
private void sort() {
if (comparator == null) {
if (reverse) {
Collections.sort(lines, new Comparator