blob: 325533e90bf370276bb7e2b357286c38d80a1ff7 [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.framework;
import java.util.*;
class FindEntriesEnumeration implements Enumeration
{
private FelixBundle m_bundle = null;
private Enumeration m_enumeration = null;
private String m_path = null;
private String[] m_filePattern = null;
private boolean m_recurse = false;
private Object m_next = null;
public FindEntriesEnumeration(
FelixBundle bundle, String path, String filePattern, boolean recurse)
{
m_bundle = bundle;
m_path = path;
m_enumeration = (m_bundle.getInfo().getCurrentModule().getContentLoader().getContent() == null)
? null : m_bundle.getInfo().getCurrentModule().getContentLoader().getContent().getEntries();
m_recurse = recurse;
// Sanity check the parameters.
if (m_path == null)
{
throw new IllegalArgumentException("The path for findEntries() cannot be null.");
}
// Strip leading '/' if present.
if ((m_path.length() > 0) && (m_path.charAt(0) == '/'))
{
m_path = m_path.substring(1);
}
// Add a '/' to the end if not present.
if ((m_path.length() > 0) && (m_path.charAt(m_path.length() - 1) != '/'))
{
m_path = m_path + "/";
}
// File pattern defaults to "*" if not specified.
filePattern = (filePattern == null) ? "*" : filePattern;
m_filePattern = parseSubstring(filePattern);
m_next = findNext();
}
public boolean hasMoreElements()
{
return (m_next != null);
}
public Object nextElement()
{
if (m_next == null)
{
throw new NoSuchElementException("No more entry paths.");
}
Object last = m_next;
m_next = findNext();
return last;
}
private Object 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.
while ((m_enumeration != null) && m_enumeration.hasMoreElements())
{
// Get the next entry name.
String entryName = (String) m_enumeration.nextElement();
// Check to see if it is a descendent of the specified path.
if (!entryName.equals(m_path) && entryName.startsWith(m_path))
{
// If this is recursive search, then try to match any
// entry path that starts with the specified path;
// otherwise, only try to match children of the specified
// path and not any grandchild. This code uses the knowledge
// that content entries corresponding to directories end in '/'.
int idx = entryName.indexOf('/', m_path.length());
if (m_recurse || (idx < 0) || (idx == (entryName.length() - 1)))
{
// Get the last element of the entry path, not including
// the '/' if it is a directory.
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;
String lastElement = entryName.substring(startIdx, endIdx);
// See if the file pattern matches the last element of the path.
if (checkSubstring(m_filePattern, lastElement))
{
// Convert entry name into an entry URL.
return m_bundle.getInfo().getCurrentModule()
.getContentLoader().getResourceFromContent(entryName);
}
}
}
}
return null;
}
//
// The following substring-related code was lifted and modified
// from the LDAP parser code.
//
private static String[] parseSubstring(String target)
{
List pieces = new ArrayList();
StringBuffer ss = new StringBuffer();
// int kind = SIMPLE; // assume until proven otherwise
boolean wasStar = false; // indicates last piece was a star
boolean leftstar = false; // track if the initial piece is a star
boolean rightstar = false; // track if the final piece is a star
int idx = 0;
// We assume (sub)strings can contain leading and trailing blanks
for (;;)
{
if (idx >= target.length())
{
if (wasStar)
{
// insert last piece as "" to handle trailing star
rightstar = true;
}
else
{
pieces.add(ss.toString());
// accumulate the last piece
// note that in the case of
// (cn=); this might be
// the string "" (!=null)
}
ss.setLength(0);
break;
}
char c = target.charAt(idx++);
if (c == '*')
{
if (wasStar)
{
// encountered two successive stars;
// I assume this is illegal
throw new IllegalArgumentException("Invalid filter string: " + target);
}
if (ss.length() > 0)
{
pieces.add(ss.toString()); // accumulate the pieces
// between '*' occurrences
}
ss.setLength(0);
// if this is a leading star, then track it
if (pieces.size() == 0)
{
leftstar = true;
}
ss.setLength(0);
wasStar = true;
}
else
{
wasStar = false;
ss.append(c);
}
}
if (leftstar || rightstar || pieces.size() > 1)
{
// insert leading and/or trailing "" to anchor ends
if (rightstar)
{
pieces.add("");
}
if (leftstar)
{
pieces.add(0, "");
}
}
return (String[]) pieces.toArray(new String[pieces.size()]);
}
private static boolean checkSubstring(String[] pieces, String s)
{
// Walk the pieces to match the string
// There are implicit stars between each piece,
// and the first and last pieces might be "" to anchor the match.
// assert (pieces.length > 1)
// minimal case is <string>*<string>
boolean result = false;
int len = pieces.length;
int index = 0;
for (int i = 0; i < len; i++)
{
String piece = (String) pieces[i];
if (i == len - 1)
{
// this is the last piece
if (s.endsWith(piece))
{
result = true;
}
else
{
result = false;
}
break;
}
// initial non-star; assert index == 0
else if (i == 0)
{
if (!s.startsWith(piece))
{
result = false;
break;
}
}
// assert i > 0 && i < len-1
else
{
// Sure wish stringbuffer supported e.g. indexOf
index = s.indexOf(piece, index);
if (index < 0)
{
result = false;
break;
}
}
// start beyond the matching piece
index += piece.length();
}
return result;
}
}