blob: 1161558013e51399f21aac3b9ee9d0b8468088e6 [file] [log] [blame]
/*
* 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.types.resources;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.types.AbstractFileSet;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceCollection;
/**
* Union of file/dirsets that share the same patterns and selectors
* but have different roots.
* @since Ant 1.9.4
*/
public class MultiRootFileSet extends AbstractFileSet
implements ResourceCollection {
private SetType type = SetType.file;
private boolean cache = true;
private List<File> baseDirs = new ArrayList<File>();
private Union union;
@Override
public void setDir(final File dir) {
throw new BuildException(getDataTypeName()
+ " doesn't support the dir attribute");
}
/**
* Determines the types of resources to return.
* @param type the types of resources to return
*/
public void setType(final SetType type) {
if (isReference()) {
throw tooManyAttributes();
}
this.type = type;
}
/**
* Set whether to cache collections.
* @param b boolean cache flag.
*/
public synchronized void setCache(final boolean b) {
if (isReference()) {
throw tooManyAttributes();
}
cache = b;
}
/**
* Adds basedirs as a comma separated list.
* @param dirs directories as CSV
*/
public void setBaseDirs(final String dirs) {
if (isReference()) {
throw tooManyAttributes();
}
if (dirs != null && dirs.length() > 0) {
final String[] ds = dirs.split(",");
for (final String d : ds) {
baseDirs.add(getProject().resolveFile(d));
}
}
}
/**
* Adds a basedir as nested element.
* @param r basedir
*/
public void addConfiguredBaseDir(final FileResource r) {
if (isReference()) {
throw noChildrenAllowed();
}
baseDirs.add(r.getFile());
}
@Override
public void setRefid(final Reference r) {
if (!baseDirs.isEmpty()) {
throw tooManyAttributes();
}
super.setRefid(r);
}
/**
* Return a MultiRootFileSet that has the same basedirs and same patternsets
* as this one.
* @return the cloned MultiRootFileSet.
*/
@Override
public Object clone() {
if (isReference()) {
return ((MultiRootFileSet) getRef(getProject())).clone();
} else {
final MultiRootFileSet fs = (MultiRootFileSet) super.clone();
fs.baseDirs = new ArrayList<File>(baseDirs);
fs.union = null;
return fs;
}
}
/**
* Fulfill the ResourceCollection contract.
* @return an Iterator of Resources.
*/
public Iterator<Resource> iterator() {
if (isReference()) {
return ((MultiRootFileSet) getRef(getProject())).iterator();
}
return merge().iterator();
}
/**
* Fulfill the ResourceCollection contract.
* @return number of elements as int.
*/
public int size() {
if (isReference()) {
return ((MultiRootFileSet) getRef(getProject())).size();
}
return merge().size();
}
/**
* Always returns true.
* @return true indicating that all elements will be FileResources.
*/
public boolean isFilesystemOnly() {
return true;
}
/**
* Returns included directories as a list of semicolon-separated paths.
*
* @return a <code>String</code> of included directories.
*/
@Override
public String toString() {
if (isReference()) {
return ((MultiRootFileSet) getRef(getProject())).toString();
}
return merge().toString();
}
private synchronized Union merge() {
if (cache && union != null) {
return union;
}
final Union u = new Union();
setup(u);
if (cache) {
union = u;
}
return u;
}
private void setup(final Union u) {
for (final File d : baseDirs) {
u.add(new Worker(this, type, d));
}
}
/**
* What to return from the set: files, directories or both.
*/
public enum SetType {
file, dir, both
}
private static class Worker extends AbstractFileSet
implements ResourceCollection {
private final SetType type;
private Worker(final MultiRootFileSet fs, final SetType type, final File dir) {
super(fs);
this.type = type;
setDir(dir);
}
public boolean isFilesystemOnly() {
return true;
}
public Iterator<Resource> iterator() {
final DirectoryScanner ds = getDirectoryScanner(getProject());
String[] names = type == SetType.file
? ds.getIncludedFiles()
: ds.getIncludedDirectories();
if (type == SetType.both) {
final String[] files = ds.getIncludedFiles();
final String[] merged = new String[names.length + files.length];
System.arraycopy(names, 0, merged, 0, names.length);
System.arraycopy(files, 0, merged, names.length, files.length);
names = merged;
}
return new FileResourceIterator(getProject(), getDir(getProject()),
names);
}
public int size() {
final DirectoryScanner ds = getDirectoryScanner(getProject());
int count = type == SetType.file
? ds.getIncludedFilesCount()
: ds.getIncludedDirsCount();
if (type == SetType.both) {
count += ds.getIncludedFilesCount();
}
return count;
}
}
}