/* * 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); } }