blob: 01c9d4daea6811c2bc15f7f0a73a60df39c0bb0d [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.felix.connect;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import org.apache.felix.connect.felix.framework.capabilityset.SimpleFilter;
class EntryFilterEnumeration<T> implements Enumeration<T>
{
private final Enumeration<String> m_enumeration;
private final Revision m_revision;
private final String m_path;
private final List<String> m_filePattern;
private final boolean m_recurse;
private final boolean m_isURLValues;
private final Set<String> m_dirEntries = new HashSet<String>();
private final List<T> m_nextEntries = new ArrayList<T>(2);
public EntryFilterEnumeration(
Revision rev,
boolean includeFragments,
String path,
String filePattern,
boolean recurse,
boolean isURLValues)
{
m_revision = rev;
m_enumeration = rev.getEntries();
m_recurse = recurse;
m_isURLValues = isURLValues;
// Sanity check the parameters.
if (path == null)
{
throw new IllegalArgumentException("The path for findEntries() cannot be null.");
}
// Strip leading '/' if present.
if ((path.length() > 0) && (path.charAt(0) == '/'))
{
path = path.substring(1);
}
// Add a '/' to the end if not present.
if ((path.length() > 0) && (path.charAt(path.length() - 1) != '/'))
{
path = path + "/";
}
m_path = path;
// File pattern defaults to "*" if not specified.
filePattern = (filePattern == null) ? "*" : filePattern;
m_filePattern = SimpleFilter.parseSubstring(filePattern);
findNext();
}
public synchronized boolean hasMoreElements()
{
return (m_nextEntries.size() != 0);
}
public synchronized T nextElement()
{
if (m_nextEntries.size() == 0)
{
throw new NoSuchElementException("No more entries.");
}
T last = m_nextEntries.remove(0);
findNext();
return last;
}
private void findNext()
{
// This method filters the content entry enumeration, such that
// it only displays the contents of the directory specified by
// the path argument either recursively or not; much like using
// "ls -R" or "ls" to list the contents of a directory, respectively.
if (m_enumeration == null)
{
return;
}
if (m_nextEntries.size() == 0)
{
while (m_enumeration.hasMoreElements() && m_nextEntries.size() == 0)
{
// Get the current entry to determine if it should be filtered
// or not.
String entryName = (String) m_enumeration.nextElement();
// Check to see if the current entry is a descendent of the
// specified path.
if (!entryName.equals(m_path) && entryName.startsWith(m_path))
{
// Cached entry URL. If we are returning URLs, we use this
// cached URL to avoid doing multiple URL lookups from a
// module
// when synthesizing directory URLs.
URL entryURL = null;
// If the current entry is in a subdirectory of the
// specified path,
// get the index of the slash character.
int dirSlashIdx = entryName.indexOf('/', m_path.length());
// JAR files are supposed to contain entries for
// directories,
// but not all do. So calculate the directory for this entry
// and see if we've already seen an entry for the directory.
// If not, synthesize an entry for the directory. If we are
// doing a recursive match, we need to synthesize each
// matching
// subdirectory of the entry.
if (dirSlashIdx >= 0)
{
// Start synthesizing directories for the current entry
// at the subdirectory after the initial path.
int subDirSlashIdx = dirSlashIdx;
String dir;
do
{
// Calculate the subdirectory name.
dir = entryName.substring(0, subDirSlashIdx + 1);
// If we have not seen this directory before, then
// record
// it and potentially synthesize an entry for it.
if (!m_dirEntries.contains(dir))
{
// Record it.
m_dirEntries.add(dir);
// If the entry is actually a directory entry
// (i.e.,
// it ends with a slash), then we don't need to
// synthesize an entry since it exists;
// otherwise,
// synthesize an entry if it matches the file
// pattern.
if (entryName.length() != (subDirSlashIdx + 1))
{
// See if the file pattern matches the last
// element of the path.
if (SimpleFilter.compareSubstring(
m_filePattern,
getLastPathElement(dir)))
{
if (m_isURLValues)
{
entryURL = (entryURL == null) ? m_revision
.getEntry(entryName)
: entryURL;
try
{
m_nextEntries.add((T) new URL(entryURL, "/" + dir));
}
catch (MalformedURLException ex)
{
}
}
else
{
m_nextEntries.add((T) dir);
}
}
}
}
// Now prepare to synthesize the next subdirectory
// if we are matching recursively.
subDirSlashIdx = entryName.indexOf('/',
dir.length());
}
while (m_recurse && (subDirSlashIdx >= 0));
}
// Now we actually need to check if the current entry itself
// should
// be filtered or not. If we are recursive or the current
// entry
// is a child (not a grandchild) of the initial path, then
// we need
// to check if it matches the file pattern.
if (m_recurse || (dirSlashIdx < 0) || (dirSlashIdx == entryName.length() - 1))
{
// See if the file pattern matches the last element of
// the path.
if (SimpleFilter.compareSubstring(m_filePattern,
getLastPathElement(entryName)))
{
if (m_isURLValues)
{
entryURL = (entryURL == null) ? m_revision
.getEntry(entryName) : entryURL;
m_nextEntries.add((T) entryURL);
}
else
{
m_nextEntries.add((T) entryName);
}
}
}
}
}
}
}
private static String getLastPathElement(String entryName)
{
int endIdx = (entryName.charAt(entryName.length() - 1) == '/') ? entryName
.length() - 1 : entryName.length();
int startIdx = (entryName.charAt(entryName.length() - 1) == '/') ? entryName
.lastIndexOf('/', endIdx - 1) + 1 : entryName.lastIndexOf('/',
endIdx) + 1;
return entryName.substring(startIdx, endIdx);
}
}