gt:         return new CompoundEnumeration((Enumeration[])
context: /*
   * 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.searchpolicy;
  
  import org.apache.felix.moduleloader.*;
  import java.io.IOException;
  import java.io.InputStream;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  import java.lang.reflect.Proxy;
  import java.net.MalformedURLException;
  import java.net.URL;
  import java.net.URLStreamHandler;
  import java.security.AccessController;
  import java.security.PrivilegedAction;
  import java.security.ProtectionDomain;
  import java.security.SecureClassLoader;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Enumeration;
  
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.Vector;
  import org.apache.felix.framework.Felix.FelixResolver;
  import org.apache.felix.framework.Logger;
  import org.apache.felix.framework.cache.JarContent;
  import org.apache.felix.framework.util.CompoundEnumeration;
  import org.apache.felix.framework.util.FelixConstants;
  import org.apache.felix.framework.util.SecureAction;
  import org.apache.felix.framework.util.SecurityManagerEx;
  import org.apache.felix.framework.util.Util;
  import org.apache.felix.framework.util.manifestparser.ManifestParser;
  import org.apache.felix.framework.util.manifestparser.R4Library;
  import org.apache.felix.framework.util.manifestparser.Requirement;
  import org.osgi.framework.Bundle;
  import org.osgi.framework.BundleException;
  import org.osgi.framework.Constants;
  import org.osgi.framework.InvalidSyntaxException;
  import org.osgi.framework.Version;
  
  public class ModuleImpl implements IModule
  {
      private final Logger m_logger;
      private final Map m_configMap;
      private final FelixResolver m_resolver;
      private final String m_id;
      private final IContent m_content;
      private final Map m_headerMap;
      private final URLStreamHandler m_streamHandler;
  
      private final String m_manifestVersion;
      private final boolean m_isExtension;
      private final String m_symbolicName;
      private final Version m_version;
  
      private final ICapability[] m_capabilities;
      private final IRequirement[] m_requirements;
      private final IRequirement[] m_dynamicRequirements;
      private final R4Library[] m_nativeLibraries;
      private final Bundle m_bundle;
  
      private IModule[] m_fragments = null;
      private IWire[] m_wires = null;
      private IModule[] m_dependentHosts = new IModule[0];
      private IModule[] m_dependentImporters = new IModule[0];
      private IModule[] m_dependentRequirers = new IModule[0];
      private volatile boolean m_isResolved = false;
  
      private IContent[] m_contentPath;
      private IContent[] m_fragmentContents = null;
      private ModuleClassLoader m_classLoader;
      private ProtectionDomain m_protectionDomain = null;
      private static SecureAction m_secureAction = new SecureAction();
  
      // Boot delegation packages.
      private final String[] m_bootPkgs;
      private final boolean[] m_bootPkgWildcards;
  
      // Re-usable security manager for accessing class context.
      private static SecurityManagerEx m_sm = new SecurityManagerEx();
  
      // Thread local to detect class loading cycles.
      private final ThreadLocal m_cycleCheck = new ThreadLocal();
  
      /**
       * This constructor is used by the extension manager, since it needs
       * a constructor that does not throw an exception.
       * @param logger
       * @param bundle
       * @param id
       * @param bootPkgs
       * @param bootPkgWildcards
       * @throws org.osgi.framework.BundleException
       */
      public ModuleImpl(
          Logger logger, Bundle bundle, String id,
          String[] bootPkgs, boolean[] bootPkgWildcards)
      {
          m_logger = logger;
          m_configMap = null;
          m_resolver = null;
          m_bundle = bundle;
          m_id = id;
          m_headerMap = null;
          m_content = null;
          m_streamHandler = null;
          m_bootPkgs = bootPkgs;
          m_bootPkgWildcards = bootPkgWildcards;
          m_manifestVersion = null;
          m_symbolicName = null;
          m_isExtension = false;
          m_version = null;
          m_capabilities = null;
          m_requirements = null;
          m_dynamicRequirements = null;
          m_nativeLibraries = null;
      }
  
      public ModuleImpl(
          Logger logger, Map configMap, FelixResolver resolver,
          Bundle bundle, String id, Map headerMap, IContent content,
          URLStreamHandler streamHandler, String[] bootPkgs,
          boolean[] bootPkgWildcards)
          throws BundleException
      {
          m_logger = logger;
          m_configMap = configMap;
          m_resolver = resolver;
          m_bundle = bundle;
          m_id = id;
          m_headerMap = headerMap;
          m_content = content;
          m_streamHandler = streamHandler;
          m_bootPkgs = bootPkgs;
          m_bootPkgWildcards = bootPkgWildcards;
  
          ManifestParser mp = new ManifestParser(m_logger, m_configMap, m_headerMap);
  
          // Record some of the parsed metadata. Note, if this is an extension
          // bundle it's exports are removed, since they will be added to the
          // system bundle directly later on.
          m_manifestVersion = mp.getManifestVersion();
          m_version = mp.getBundleVersion();
          m_capabilities = mp.isExtension() ? null : mp.getCapabilities();
          m_requirements = mp.getRequirements();
          m_dynamicRequirements = mp.getDynamicRequirements();
          m_nativeLibraries = mp.getLibraries();
          m_symbolicName = mp.getSymbolicName();
          m_isExtension = mp.isExtension();
  
          // Verify that all native libraries exist in advance; this will
          // throw an exception if the native library does not exist.
          try
          {
              for (int i = 0;
                  (m_nativeLibraries != null) && (i < m_nativeLibraries.length);
                  i++)
              {
                  String entryName = m_nativeLibraries[i].getEntryName();
                  if (entryName != null)
                  {
                      if (m_content.getEntryAsNativeLibrary(entryName) == null)
                      {
                          throw new BundleException("Native library does not exist: " + entryName);
                      }
                  }
              }
          }
          finally
          {
              // We close the module content here to make sure it is closed
              // to avoid having to close it if there is an exception during
              // the entire module creation process.
  // TODO: REFACTOR - If we do the above check here, then we open the module's content
  //       immediately every time, which means we must close it here so we don't have
  //       to remember to close it if there are other failures during module init.
              m_content.close();
          }
      }
  
      //
      // Metadata access methods.
      //
  
      public Map getHeaders()
      {
          return m_headerMap;
      }
  
      public boolean isExtension()
      {
          return m_isExtension;
      }
  
      public String getSymbolicName()
      {
          return m_symbolicName;
      }
  
      public String getManifestVersion()
      {
          return m_manifestVersion;
      }
  
      public Version getVersion()
      {
          return m_version;
      }
  
      public synchronized ICapability[] getCapabilities()
      {
          List capList = (m_capabilities == null)
              ? new ArrayList() : new ArrayList(Arrays.asList(m_capabilities));
          for (int fragIdx = 0;
              (m_fragments != null) && (fragIdx < m_fragments.length);
              fragIdx++)
          {
              ICapability[] caps = m_fragments[fragIdx].getCapabilities();
              for (int capIdx = 0;
                  (caps != null) && (capIdx < caps.length);
                  capIdx++)
              {
                  if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
                  {
                      capList.add(caps[capIdx]);
                  }
              }
          }
          return (ICapability[]) capList.toArray(new ICapability[capList.size()]);
      }
  
      public synchronized IRequirement[] getRequirements()
      {
          List reqList = (m_requirements == null)
              ? new ArrayList() : new ArrayList(Arrays.asList(m_requirements));
          for (int fragIdx = 0;
              (m_fragments != null) && (fragIdx < m_fragments.length);
              fragIdx++)
          {
              IRequirement[] reqs = m_fragments[fragIdx].getRequirements();
              for (int reqIdx = 0;
                  (reqs != null) && (reqIdx < reqs.length);
                  reqIdx++)
              {
                  if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE)
                      || reqs[reqIdx].getNamespace().equals(ICapability.MODULE_NAMESPACE))
                  {
                      reqList.add(reqs[reqIdx]);
                  }
              }
          }
          return (IRequirement[]) reqList.toArray(new IRequirement[reqList.size()]);
      }
  
      public synchronized IRequirement[] getDynamicRequirements()
      {
          List reqList = (m_dynamicRequirements == null)
              ? new ArrayList() : new ArrayList(Arrays.asList(m_dynamicRequirements));
          for (int fragIdx = 0;
              (m_fragments != null) && (fragIdx < m_fragments.length);
              fragIdx++)
          {
              IRequirement[] reqs = m_fragments[fragIdx].getDynamicRequirements();
              for (int reqIdx = 0;
                  (reqs != null) && (reqIdx < reqs.length);
                  reqIdx++)
              {
                  if (reqs[reqIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
                  {
                      reqList.add(reqs[reqIdx]);
                  }
              }
          }
          return (IRequirement[]) reqList.toArray(new IRequirement[reqList.size()]);
      }
  
      public R4Library[] getNativeLibraries()
      {
          return m_nativeLibraries;
      }
  
      //
      // Run-time data access.
      //
  
      public Bundle getBundle()
      {
          return m_bundle;
      }
  
      public String getId()
      {
          return m_id;
      }
  
      public synchronized IWire[] getWires()
      {
          return m_wires;
      }
  
      public synchronized void setWires(IWire[] wires)
      {
          // Remove module from old wire modules' dependencies,
          // since we are no longer dependent on any the moduels
          // from the old wires.
          for (int i = 0; (m_wires != null) && (i < m_wires.length); i++)
          {
              if (m_wires[i].getCapability().getNamespace().equals(ICapability.MODULE_NAMESPACE))
              {
                  ((ModuleImpl) m_wires[i].getExporter()).removeDependentRequirer(this);
              }
              else if (m_wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
              {
                  ((ModuleImpl) m_wires[i].getExporter()).removeDependentImporter(this);
              }
          }
  
          m_wires = wires;
  
          // Add ourself as a dependent to the new wires' modules.
          for (int i = 0; (m_wires != null) && (i < m_wires.length); i++)
          {
              if (m_wires[i].getCapability().getNamespace().equals(ICapability.MODULE_NAMESPACE))
              {
                  ((ModuleImpl) m_wires[i].getExporter()).addDependentRequirer(this);
              }
              else if (m_wires[i].getCapability().getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
              {
                  ((ModuleImpl) m_wires[i].getExporter()).addDependentImporter(this);
              }
          }
      }
  
      public boolean isResolved()
      {
          return m_isResolved;
      }
  
      public void setResolved()
      {
          m_isResolved = true;
      }
  
      //
      // Content access methods.
      //
  
      public IContent getContent()
      {
          return m_content;
      }
  
      private synchronized IContent[] getContentPath()
      {
          if (m_contentPath == null)
          {
              try
              {
                  m_contentPath = initializeContentPath();
              }
              catch (Exception ex)
              {
                  m_logger.log(Logger.LOG_ERROR, "Unable to get module class path.", ex);
              }
          }
          return m_contentPath;
      }
  
      private IContent[] initializeContentPath() throws Exception
      {
          List contentList = new ArrayList();
          calculateContentPath(this, m_content, contentList, true);
          for (int i = 0; (m_fragmentContents != null) && (i < m_fragmentContents.length); i++)
          {
              calculateContentPath(m_fragments[i], m_fragmentContents[i], contentList, false);
          }
          return (IContent[]) contentList.toArray(new IContent[contentList.size()]);
      }
  
      private List calculateContentPath(
          IModule module, IContent content, List contentList, boolean searchFragments)
          throws Exception
      {
          // Creating the content path entails examining the bundle's
          // class path to determine whether the bundle JAR file itself
          // is on the bundle's class path and then creating content
          // objects for everything on the class path.
  
          // Create a list to contain the content path for the specified content.
          List localContentList = new ArrayList();
  
          // Find class path meta-data.
          String classPath = (String) module.getHeaders().get(FelixConstants.BUNDLE_CLASSPATH);
          // Parse the class path into strings.
          String[] classPathStrings = ManifestParser.parseDelimitedString(
              classPath, FelixConstants.CLASS_PATH_SEPARATOR);
  
          if (classPathStrings == null)
          {
              classPathStrings = new String[0];
          }
  
          // Create the bundles class path.
          for (int i = 0; i < classPathStrings.length; i++)
          {
              // Remove any leading slash, since all bundle class path
              // entries are relative to the root of the bundle.
              classPathStrings[i] = (classPathStrings[i].startsWith("/"))
                  ? classPathStrings[i].substring(1)
                  : classPathStrings[i];
  
              // Check for the bundle itself on the class path.
              if (classPathStrings[i].equals(FelixConstants.CLASS_PATH_DOT))
              {
                  localContentList.add(content);
              }
              else
              {
                  // Try to find the embedded class path entry in the current
                  // content.
                  IContent embeddedContent = content.getEntryAsContent(classPathStrings[i]);
                  // If the embedded class path entry was not found, it might be
                  // in one of the fragments if the current content is the bundle,
                  // so try to search the fragments if necessary.
                  for (int fragIdx = 0;
                      searchFragments && (embeddedContent == null)
                          && (m_fragmentContents != null) && (fragIdx < m_fragmentContents.length);
                      fragIdx++)
                  {
                      embeddedContent = m_fragmentContents[fragIdx].getEntryAsContent(classPathStrings[i]);
                  }
                  // If we found the embedded content, then add it to the
                  // class path content list.
                  if (embeddedContent != null)
                  {
                      localContentList.add(embeddedContent);
                  }
                  else
                  {
  // TODO: FRAMEWORK - Per the spec, this should fire a FrameworkEvent.INFO event;
  //       need to create an "Eventer" class like "Logger" perhaps.
                      m_logger.log(Logger.LOG_INFO,
                          "Class path entry not found: "
                          + classPathStrings[i]);
                  }
              }
          }
  
          // If there is nothing on the class path, then include
          // "." by default, as per the spec.
          if (localContentList.size() == 0)
          {
              localContentList.add(content);
          }
  
          // Now add the local contents to the global content list and return it.
          contentList.addAll(localContentList);
          return contentList;
      }
  
      public Class getClassByDelegation(String name) throws ClassNotFoundException
      {
          // We do not call getClassLoader().loadClass() for arrays because
          // it does not correctly handle array types, which is necessary in
          // cases like deserialization using a wrapper class loader.
          if (name.charAt(0) == '[')
          {
              return Class.forName(name, false, getClassLoader());
          }
          return getClassLoader().loadClass(name);
      }
  
      public URL getResourceByDelegation(String name)
      {
          try
          {
              return (URL) findClassOrResourceByDelegation(name, false);
          }
          catch (ClassNotFoundException ex)
          {
              // This should never be thrown because we are loading resources.
          }
          catch (ResourceNotFoundException ex)
          {
              m_logger.log(
                  Logger.LOG_DEBUG,
                  ex.getMessage(),
                  ex);
          }
          return null;
      }
  
      private Object findClassOrResourceByDelegation(String name, boolean isClass)
          throws ClassNotFoundException, ResourceNotFoundException
      {
          Object result = null;
  
          Set requestSet = (Set) m_cycleCheck.get();
          if (requestSet == null)
          {
              requestSet = new HashSet();
              m_cycleCheck.set(requestSet);
          }
          if (requestSet.add(name))
          {
              try
              {
                  // First, try to resolve the originating module.
                  m_resolver.resolve(this);
  
                  // Get the package of the target class/resource.
                  String pkgName = (isClass)
                      ? Util.getClassPackage(name)
                      : Util.getResourcePackage(name);
  
                  // Delegate any packages listed in the boot delegation
                  // property to the parent class loader.
                  if (shouldBootDelegate(pkgName))
                  {
                      try
                      {
                          result = (isClass)
                              ? (Object) getClass().getClassLoader().loadClass(name)
                              : (Object) getClass().getClassLoader().getResource(name);
                          // If this is a java.* package, then always terminate the
                          // search; otherwise, continue to look locally if not found.
                          if (pkgName.startsWith("java.") || (result != null))
                          {
                              return result;
                          }
                      }
                      catch (ClassNotFoundException ex)
                      {
                          // If this is a java.* package, then always terminate the
                          // search; otherwise, continue to look locally if not found.
                          if (pkgName.startsWith("java."))
                          {
                              throw ex;
                          }
                      }
                  }
  
                  // Look in the module's imports. Note that the search may
                  // be aborted if this method throws an exception, otherwise
                  // it continues if a null is returned.
                  result = searchImports(name, isClass);
  
                  // If not found, try the module's own class path.
                  if (result == null)
                  {
                      result = (isClass)
                          ? (Object) getClassLoader().findClass(name)
                          : (Object) getResourceLocal(name);
  
                      // If still not found, then try the module's dynamic imports.
                      if (result == null)
                      {
                          result = searchDynamicImports(name, pkgName, isClass);
                      }
                  }
              }
              catch (ResolveException ex)
              {
                  if (isClass)
                  {
                      // We do not use the resolve exception as the
                      // cause of the exception, since this would
                      // potentially leak internal module information.
                      throw new ClassNotFoundException(
                          name + ": cannot resolve package "
                          + ex.getRequirement());
                  }
                  else
                  {
                      // The spec states that if the bundle cannot be resolved, then
                      // only the local bundle's resources should be searched. So we
                      // will ask the module's own class path.
                      URL url = getResourceLocal(name);
                      if (url != null)
                      {
                          return url;
                      }
  
                      // We need to throw a resource not found exception.
                      throw new ResourceNotFoundException(
                          name + ": cannot resolve package "
                          + ex.getRequirement());
                  }
              }
              finally
              {
                  requestSet.remove(name);
              }
          }
          else
          {
              // If a cycle is detected, we should return null to break the
              // cycle. This should only ever be return to internal class
              // loading code and not to the actual instigator of the class load.
              return null;
          }
  
          if (result == null)
          {
              if (isClass)
              {
                  throw new ClassNotFoundException(name);
              }
              else
              {
                  throw new ResourceNotFoundException(name);
              }
          }
  
          return result;
      }
  
      private URL getResourceLocal(String name)
      {
          URL url = null;
  
          // Remove leading slash, if present, but special case
          // "/" so that it returns a root URL...this isn't very
          // clean or meaninful, but the Spring guys want it.
          if (name.equals("/"))
          {
              // Just pick a class path index since it doesn't really matter.
              url = createURL(1, name);
          }
          else if (name.startsWith("/"))
          {
              name = name.substring(1);
          }
  
          // Check the module class path.
          IContent[] contentPath = getContentPath();
          for (int i = 0;
              (url == null) &&
              (i < contentPath.length); i++)
          {
              if (contentPath[i].hasEntry(name))
              {
                  url = createURL(i + 1, name);
              }
          }
  
          return url;
      }
  
      public Enumeration getResourcesByDelegation(String name)
      {
          Set requestSet = (Set) m_cycleCheck.get();
          if (requestSet == null)
          {
              requestSet = new HashSet();
              m_cycleCheck.set(requestSet);
          }
          if (!requestSet.contains(name))
          {
              requestSet.add(name);
              try
              {
                  return findResourcesByDelegation(name);
              }
              finally
              {
                  requestSet.remove(name);
              }
          }
  
          return null;
      }
  
      private Enumeration findResourcesByDelegation(String name)
      {
          Enumeration urls = null;
          List completeUrlList = new ArrayList();
  
          // First, try to resolve the originating module.
          try
          {
              m_resolver.resolve(this);
          }
          catch (ResolveException ex)
          {
              // The spec states that if the bundle cannot be resolved, then
              // only the local bundle's resources should be searched. So we
              // will ask the module's own class path.
              urls = getResourcesLocal(name);
              return urls;
          }
  
          // Get the package of the target class/resource.
          String pkgName = Util.getResourcePackage(name);
  
          // Delegate any packages listed in the boot delegation
          // property to the parent class loader.
          if (shouldBootDelegate(pkgName))
          {
              try
              {
                  urls = getClass().getClassLoader().getResources(name);
              }
              catch (IOException ex)
              {
                  // This shouldn't happen and even if it does, there
                  // is nothing we can do, so just ignore it.
              }
              // If this is a java.* package, then always terminate the
              // search; otherwise, continue to look locally.
              if (pkgName.startsWith("java."))
              {
                  return urls;
              }
  
              completeUrlList.add(urls);
          }
  
          // Look in the module's imports.
          // We delegate to the module's wires for the resources.
          // If any resources are found, this means that the package of these
          // resources is imported, we must not keep looking since we do not
          // support split-packages.
  
          // Note that the search may be aborted if this method throws an
          // exception, otherwise it continues if a null is returned.
          IWire[] wires = getWires();
          for (int i = 0; (wires != null) && (i < wires.length); i++)
          {
              if (wires[i] instanceof R4Wire)
              {
                  try
                  {
                      // If we find the class or resource, then return it.
                      urls = wires[i].getResources(name);
                  }
                  catch (ResourceNotFoundException ex)
                  {
                      urls = null;
                  }
                  if (urls != null)
                  {
                      completeUrlList.add(urls);
                      return new CompoundEnumeration((Enumeration[])
                          completeUrlList.toArray(new Enumeration[completeUrlList.size()]));
                  }
              }
          }
  
          // See whether we can get the resource from the required bundles and
          // regardless of whether or not this is the case continue to the next
          // step potentially passing on the result of this search (if any).
          for (int i = 0; (wires != null) && (i < wires.length); i++)
          {
              if (wires[i] instanceof R4WireModule)
              {
                  try
                  {
                      // If we find the class or resource, then add it.
                      urls = wires[i].getResources(name);
                  }
                  catch (ResourceNotFoundException ex)
                  {
                      urls = null;
                  }
                  if (urls != null)
                  {
                      completeUrlList.add(urls);
                  }
              }
          }
  
          // Try the module's own class path. If we can find the resource then
          // return it together with the results from the other searches else
          // try to look into the dynamic imports.
          urls = getResourcesLocal(name);
          if (urls != null)
          {
              completeUrlList.add(urls);
          }
          else
          {
              // If not found, then try the module's dynamic imports.
              // At this point, the module's imports were searched and so was the
              // the module's content. Now we make an attempt to load the
              // class/resource via a dynamic import, if possible.
              IWire wire = null;
              try
              {
                  wire = m_resolver.resolveDynamicImport(this, pkgName);
              }
              catch (ResolveException ex)
              {
                  // Ignore this since it is likely normal.
              }
              if (wire != null)
              {
                  try
                  {
                      urls = wire.getResources(name);
                  }
                  catch (ResourceNotFoundException ex)
                  {
                      urls = null;
                  }
                  if (urls != null)
                  {
                      completeUrlList.add(urls);
                  }
              }
          }
  
  