Return-Path: Delivered-To: apmail-felix-commits-archive@www.apache.org Received: (qmail 28154 invoked from network); 7 Jun 2010 20:40:45 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 7 Jun 2010 20:40:45 -0000 Received: (qmail 99722 invoked by uid 500); 7 Jun 2010 20:40:45 -0000 Delivered-To: apmail-felix-commits-archive@felix.apache.org Received: (qmail 99685 invoked by uid 500); 7 Jun 2010 20:40:45 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 99678 invoked by uid 99); 7 Jun 2010 20:40:45 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 07 Jun 2010 20:40:45 +0000 X-ASF-Spam-Status: No, hits=-1691.5 required=10.0 tests=ALL_TRUSTED,AWL X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 07 Jun 2010 20:40:42 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 02A5923889E7; Mon, 7 Jun 2010 20:40:22 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r952424 [2/3] - in /felix/sandbox/rickhall/framework-vb: ./ src/main/java/org/apache/felix/framework/ src/main/java/org/apache/felix/framework/ext/ src/main/java/org/apache/felix/framework/resolver/ src/main/java/org/apache/felix/framework/... Date: Mon, 07 Jun 2010 20:40:21 -0000 To: commits@felix.apache.org From: rickhall@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100607204022.02A5923889E7@eris.apache.org> Modified: felix/sandbox/rickhall/framework-vb/src/main/java/org/apache/felix/framework/ModuleImpl.java URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-vb/src/main/java/org/apache/felix/framework/ModuleImpl.java?rev=952424&r1=952423&r2=952424&view=diff ============================================================================== --- felix/sandbox/rickhall/framework-vb/src/main/java/org/apache/felix/framework/ModuleImpl.java (original) +++ felix/sandbox/rickhall/framework-vb/src/main/java/org/apache/felix/framework/ModuleImpl.java Mon Jun 7 20:40:20 2010 @@ -18,67 +18,39 @@ */ package org.apache.felix.framework; -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.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; -import java.security.SecureClassLoader; import java.util.ArrayList; import java.util.Collections; 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.cache.JarContent; -import org.apache.felix.framework.capabilityset.Attribute; import org.apache.felix.framework.capabilityset.Capability; import org.apache.felix.framework.capabilityset.Directive; import org.apache.felix.framework.capabilityset.Requirement; import org.apache.felix.framework.capabilityset.SimpleFilter; +import org.apache.felix.framework.ext.VirtualContent; import org.apache.felix.framework.resolver.Content; import org.apache.felix.framework.resolver.Module; import org.apache.felix.framework.resolver.ResolveException; -import org.apache.felix.framework.resolver.ResourceNotFoundException; import org.apache.felix.framework.resolver.Wire; -import org.apache.felix.framework.resolver.WireImpl; -import org.apache.felix.framework.resolver.WireModuleImpl; -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.CapabilityImpl; import org.apache.felix.framework.util.manifestparser.ManifestParser; import org.apache.felix.framework.util.manifestparser.R4Library; -import org.apache.felix.framework.util.manifestparser.RequirementImpl; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; -import org.osgi.framework.BundleReference; -import org.osgi.framework.Constants; import org.osgi.framework.Version; public class ModuleImpl implements Module { private final Logger m_logger; private final Map m_configMap; - private final FelixResolver m_resolver; private final String m_id; - private final Content m_content; + private final VirtualContent m_virtualContent; private final Map m_headerMap; - private final URLStreamHandler m_streamHandler; private final String m_manifestVersion; private final boolean m_isExtension; @@ -105,55 +77,8 @@ public class ModuleImpl implements Modul private List m_dependentRequirers = new ArrayList(0); private volatile boolean m_isResolved = false; - private Content[] m_contentPath; - private Content[] m_fragmentContents = null; - private ModuleClassLoader m_classLoader; private boolean m_isActivationTriggered = false; private ProtectionDomain m_protectionDomain = null; - private static final SecureAction m_secureAction = new SecureAction(); - - // Bundle-specific class loader for boot delegation. - private final ClassLoader m_bootClassLoader; - // Default class loader for boot delegation. - private final static ClassLoader m_defBootClassLoader; - - // Statically define the default class loader for boot delegation. - static - { - ClassLoader cl = null; - try - { - Constructor ctor = m_secureAction.getDeclaredConstructor( - SecureClassLoader.class, new Class[] { ClassLoader.class }); - m_secureAction.setAccesssible(ctor); - cl = (ClassLoader) m_secureAction.invoke(ctor, new Object[] { null }); - } - catch (Throwable ex) - { - // On Android we get an exception if we set the parent class loader - // to null, so we will work around that case by setting the parent - // class loader to the system class loader in getClassLoader() below. - cl = null; - System.err.println("Problem creating boot delegation class loader: " + ex); - } - m_defBootClassLoader = cl; - } - - // Boot delegation packages. - private final String[] m_bootPkgs; - private final boolean[] m_bootPkgWildcards; - - // Boolean flag to enable/disable implicit boot delegation. - private final boolean m_implicitBootDelegation; - - // 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(); - - // Thread local to keep track of deferred activation. - private static final ThreadLocal m_deferredActivation = new ThreadLocal(); /** * This constructor is used by the extension manager, since it needs @@ -171,14 +96,10 @@ public class ModuleImpl implements Modul { m_logger = logger; m_configMap = configMap; - 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_virtualContent = null; m_manifestVersion = null; m_symbolicName = null; m_isExtension = false; @@ -190,8 +111,6 @@ public class ModuleImpl implements Modul m_declaredActivationPolicy = EAGER_ACTIVATION; m_activationExcludes = null; m_activationIncludes = null; - m_implicitBootDelegation = false; - m_bootClassLoader = m_defBootClassLoader; } public ModuleImpl( @@ -203,32 +122,9 @@ public class ModuleImpl implements Modul { 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; - - m_implicitBootDelegation = - (m_configMap.get(FelixConstants.IMPLICIT_BOOT_DELEGATION_PROP) == null) - || Boolean.valueOf( - (String) m_configMap.get( - FelixConstants.IMPLICIT_BOOT_DELEGATION_PROP)).booleanValue(); - - ClassLoader bootLoader = m_defBootClassLoader; - Object map = m_configMap.get(FelixConstants.BOOT_CLASSLOADERS_PROP); - if (map instanceof Map) - { - Object l = ((Map) map).get(bundle); - if (l instanceof ClassLoader) - { - bootLoader = (ClassLoader) l; - } - } - m_bootClassLoader = bootLoader; ManifestParser mp = new ManifestParser(m_logger, m_configMap, this, m_headerMap); @@ -250,6 +146,11 @@ public class ModuleImpl implements Modul : ManifestParser.parseDelimitedString(mp.getActivationIncludeDirective(), ","); m_symbolicName = mp.getSymbolicName(); m_isExtension = mp.isExtension(); + + m_virtualContent = new VirtualContentImpl( + logger, configMap, streamHandler, resolver, this, + content, bootPkgs, bootPkgWildcards, + m_activationIncludes, m_activationExcludes); } // @@ -461,8 +362,21 @@ public class ModuleImpl implements Modul return m_wires; } - public synchronized void setWires(List wires) + public synchronized void resolve(List wires) throws ResolveException { + // First try to inject wires into our virtual content. + try + { + if (m_virtualContent != null) + { + m_virtualContent.resolve(wires); + } + } + catch (BundleException ex) + { + throw new ResolveException(ex.getMessage(), this, null); + } + // Remove module from old wire modules' dependencies, // since we are no longer dependent on any the moduels // from the old wires. @@ -508,753 +422,142 @@ public class ModuleImpl implements Modul // Content access methods. // - public Content getContent() + public VirtualContent getVirtualContent() { - return m_content; + return m_virtualContent; } - private synchronized Content[] getContentPath() + public Class getClassByDelegation(String name) throws ClassNotFoundException { - 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; + return m_virtualContent.loadClass(name); } - private Content[] initializeContentPath() throws Exception + public URL getResourceByDelegation(String name) { - 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.get(i), m_fragmentContents[i], contentList, false); - } - return (Content[]) contentList.toArray(new Content[contentList.size()]); + return m_virtualContent.getResource(name); } - private List calculateContentPath( - Module module, Content content, List contentList, boolean searchFragments) - throws Exception + public Enumeration getResourcesByDelegation(String name) { - // 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. - List classPathStrings = ManifestParser.parseDelimitedString( - classPath, FelixConstants.CLASS_PATH_SEPARATOR); - - if (classPathStrings == null) - { - classPathStrings = new ArrayList(0); - } - - // Create the bundles class path. - for (int i = 0; i < classPathStrings.size(); i++) - { - // Remove any leading slash, since all bundle class path - // entries are relative to the root of the bundle. - classPathStrings.set(i, (classPathStrings.get(i).startsWith("/")) - ? classPathStrings.get(i).substring(1) - : classPathStrings.get(i)); - - // Check for the bundle itself on the class path. - if (classPathStrings.get(i).equals(FelixConstants.CLASS_PATH_DOT)) - { - localContentList.add(content); - } - else - { - // Try to find the embedded class path entry in the current - // content. - Content embeddedContent = content.getEntryAsContent(classPathStrings.get(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.get(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.get(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; + return m_virtualContent.getResources(name); } - public Class getClassByDelegation(String name) throws ClassNotFoundException + public URL getEntry(String name) { - // 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 != null) && (name.length() > 0) && (name.charAt(0) == '[')) - { - return Class.forName(name, false, getClassLoader()); - } - return getClassLoader().loadClass(name); + return m_virtualContent.getEntry(name); } - public URL getResourceByDelegation(String name) + // + // Fragment and dependency management methods. + // + + public synchronized List getFragments() { - 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()); - } - return null; + return m_fragments; } - private Object findClassOrResourceByDelegation(String name, boolean isClass) - throws ClassNotFoundException, ResourceNotFoundException + public synchronized void attachFragments(List fragments) throws Exception { - Object result = null; - - Set requestSet = (Set) m_cycleCheck.get(); - if (requestSet == null) + // Remove module from old fragment dependencies. + // We will generally only remove module fragment + // dependencies when we are uninstalling the module. + for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++) { - requestSet = new HashSet(); - m_cycleCheck.set(requestSet); + ((ModuleImpl) m_fragments.get(i)).removeDependentHost(this); } - 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 - { - // Get the appropriate class loader for delegation. - ClassLoader bdcl = getBootDelegationClassLoader(); - result = (isClass) - ? (Object) bdcl.loadClass(name) - : (Object) bdcl.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); + // Remove cached capabilities and requirements. + m_cachedCapabilities = null; + m_cachedRequirements = null; + m_cachedDynamicRequirements = null; - // 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; - } + // Update the dependencies on the new fragments. + m_fragments = fragments; - // We need to throw a resource not found exception. - throw new ResourceNotFoundException( - name + ": cannot resolve package " - + ex.getRequirement()); - } - } - finally + // We need to add ourself as a dependent of each fragment module. + if (m_fragments != null) + { + for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++) { - requestSet.remove(name); + ((ModuleImpl) m_fragments.get(i)).addDependentHost(this); } } - 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) + // Now actually actually attach the fragments to our virtual content. + if (m_virtualContent != null) { - if (isClass) - { - throw new ClassNotFoundException(name); - } - else - { - throw new ResourceNotFoundException(name); - } + ((VirtualContentImpl) m_virtualContent).attachFragments(fragments); } - - return result; } - URL getResourceLocal(String name) + public synchronized List getDependentHosts() { - 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. - Content[] contentPath = getContentPath(); - for (int i = 0; - (url == null) && - (i < contentPath.length); i++) - { - if (contentPath[i].hasEntry(name)) - { - url = createURL(i + 1, name); - } - } - - return url; + return m_dependentHosts; } - public Enumeration getResourcesByDelegation(String name) + public synchronized void addDependentHost(Module module) { - Set requestSet = (Set) m_cycleCheck.get(); - if (requestSet == null) - { - requestSet = new HashSet(); - m_cycleCheck.set(requestSet); - } - if (!requestSet.contains(name)) + if (!m_dependentHosts.contains(module)) { - requestSet.add(name); - try - { - Enumeration urls = findResourcesByDelegation(name); - return (urls.hasMoreElements()) ? urls : null; - } - finally - { - requestSet.remove(name); - } + m_dependentHosts.add(module); } - - return null; } - private Enumeration findResourcesByDelegation(String name) + public synchronized void removeDependentHost(Module module) { - 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 - { - // Get the appropriate class loader for delegation. - ClassLoader bdcl = getBootDelegationClassLoader(); - urls = bdcl.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. - List wires = getWires(); - for (int i = 0; (wires != null) && (i < wires.size()); i++) - { - if (wires.get(i) instanceof WireImpl) - { - try - { - // If we find the class or resource, then return it. - urls = wires.get(i).getResources(name); - } - catch (ResourceNotFoundException ex) - { - urls = null; - } - if (urls != null) - { - completeUrlList.add(urls); - return new CompoundEnumeration((Enumeration[]) - completeUrlList.toArray(new Enumeration[completeUrlList.size()])); - } - } - } + m_dependentHosts.remove(module); + } - // 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.size()); i++) - { - if (wires.get(i) instanceof WireModuleImpl) - { - try - { - // If we find the class or resource, then add it. - urls = wires.get(i).getResources(name); - } - catch (ResourceNotFoundException ex) - { - urls = null; - } - if (urls != null) - { - completeUrlList.add(urls); - } - } - } + public synchronized List getDependentImporters() + { + return m_dependentImporters; + } - // 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) && (urls.hasMoreElements())) - { - completeUrlList.add(urls); - } - else + public synchronized void addDependentImporter(Module module) + { + if (!m_dependentImporters.contains(module)) { - // 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. - Wire wire = null; - try - { - wire = m_resolver.resolve(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); - } - } + m_dependentImporters.add(module); } + } - return new CompoundEnumeration((Enumeration[]) - completeUrlList.toArray(new Enumeration[completeUrlList.size()])); + public synchronized void removeDependentImporter(Module module) + { + m_dependentImporters.remove(module); } - private Enumeration getResourcesLocal(String name) + public synchronized List getDependentRequirers() { - Vector v = new Vector(); + return m_dependentRequirers; + } - // Special case "/" so that it returns a root URLs for - // each bundle class path entry...this isn't very - // clean or meaningful, but the Spring guys want it. - final Content[] contentPath = getContentPath(); - if (name.equals("/")) + public synchronized void addDependentRequirer(Module module) + { + if (!m_dependentRequirers.contains(module)) { - for (int i = 0; i < contentPath.length; i++) - { - v.addElement(createURL(i + 1, name)); - } + m_dependentRequirers.add(module); } - else - { - // Remove leading slash, if present. - if (name.startsWith("/")) - { - name = name.substring(1); - } + } - // Check the module class path. - for (int i = 0; i < contentPath.length; i++) - { - if (contentPath[i].hasEntry(name)) - { - // Use the class path index + 1 for creating the path so - // that we can differentiate between module content URLs - // (where the path will start with 0) and module class - // path URLs. - v.addElement(createURL(i + 1, name)); - } - } - } + public synchronized void removeDependentRequirer(Module module) + { + m_dependentRequirers.remove(module); + } - return v.elements(); + public synchronized List getDependents() + { + List dependents = new ArrayList + (m_dependentHosts.size() + m_dependentImporters.size() + m_dependentRequirers.size()); + dependents.addAll(m_dependentHosts); + dependents.addAll(m_dependentImporters); + dependents.addAll(m_dependentRequirers); + return dependents; } - // TODO: API: Investigate how to handle this better, perhaps we need - // multiple URL policies, one for content -- one for class path. - public URL getEntry(String name) + public void close() { - URL url = null; - - // Check for the special case of "/", which represents - // the root of the bundle according to the spec. - if (name.equals("/")) - { - url = createURL(0, "/"); - } - - if (url == null) - { - // Remove leading slash, if present. - if (name.startsWith("/")) - { - name = name.substring(1); - } - - // Check the module content. - if (getContent().hasEntry(name)) - { - // Module content URLs start with 0, whereas module - // class path URLs start with the index into the class - // path + 1. - url = createURL(0, name); - } - } - - return url; - } - - public boolean hasInputStream(int index, String urlPath) - { - if (urlPath.startsWith("/")) - { - urlPath = urlPath.substring(1); - } - if (index == 0) - { - return m_content.hasEntry(urlPath); - } - return getContentPath()[index - 1].hasEntry(urlPath); - } - - public InputStream getInputStream(int index, String urlPath) - throws IOException - { - if (urlPath.startsWith("/")) - { - urlPath = urlPath.substring(1); - } - if (index == 0) - { - return m_content.getEntryAsStream(urlPath); - } - return getContentPath()[index - 1].getEntryAsStream(urlPath); - } - - private URL createURL(int port, String path) - { - // Add a slash if there is one already, otherwise - // the is no slash separating the host from the file - // in the resulting URL. - if (!path.startsWith("/")) - { - path = "/" + path; - } - - try - { - return m_secureAction.createURL(null, - FelixConstants.BUNDLE_URL_PROTOCOL + "://" + - m_id + ":" + port + path, m_streamHandler); - } - catch (MalformedURLException ex) - { - m_logger.log( - Logger.LOG_ERROR, - "Unable to create resource URL.", - ex); - } - return null; - } - - // - // Fragment and dependency management methods. - // - - public synchronized List getFragments() - { - return m_fragments; - } - - public synchronized void attachFragments(List fragments) throws Exception - { - // Remove module from old fragment dependencies. - // We will generally only remove module fragment - // dependencies when we are uninstalling the module. - for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++) - { - ((ModuleImpl) m_fragments.get(i)).removeDependentHost(this); - } - - // Remove cached capabilities and requirements. - m_cachedCapabilities = null; - m_cachedRequirements = null; - m_cachedDynamicRequirements = null; - - // Update the dependencies on the new fragments. - m_fragments = fragments; - - // We need to add ourself as a dependent of each fragment - // module. We also need to create an array of fragment contents - // to attach to our content loader. - if (m_fragments != null) - { - Content[] fragmentContents = new Content[m_fragments.size()]; - for (int i = 0; (m_fragments != null) && (i < m_fragments.size()); i++) - { - ((ModuleImpl) m_fragments.get(i)).addDependentHost(this); - fragmentContents[i] = - m_fragments.get(i).getContent() - .getEntryAsContent(FelixConstants.CLASS_PATH_DOT); - } - // Now attach the fragment contents to our content loader. - attachFragmentContents(fragmentContents); - } - } - - // This must be called holding the object lock. - private void attachFragmentContents(Content[] fragmentContents) - throws Exception - { - // Close existing fragment contents. - if (m_fragmentContents != null) - { - for (int i = 0; i < m_fragmentContents.length; i++) - { - m_fragmentContents[i].close(); - } - } - m_fragmentContents = fragmentContents; - - if (m_contentPath != null) - { - for (int i = 0; i < m_contentPath.length; i++) - { - m_contentPath[i].close(); - } - } - m_contentPath = initializeContentPath(); - } - - public synchronized List getDependentHosts() - { - return m_dependentHosts; - } - - public synchronized void addDependentHost(Module module) - { - if (!m_dependentHosts.contains(module)) - { - m_dependentHosts.add(module); - } - } - - public synchronized void removeDependentHost(Module module) - { - m_dependentHosts.remove(module); - } - - public synchronized List getDependentImporters() - { - return m_dependentImporters; - } - - public synchronized void addDependentImporter(Module module) - { - if (!m_dependentImporters.contains(module)) - { - m_dependentImporters.add(module); - } - } - - public synchronized void removeDependentImporter(Module module) - { - m_dependentImporters.remove(module); - } - - public synchronized List getDependentRequirers() - { - return m_dependentRequirers; - } - - public synchronized void addDependentRequirer(Module module) - { - if (!m_dependentRequirers.contains(module)) - { - m_dependentRequirers.add(module); - } - } - - public synchronized void removeDependentRequirer(Module module) - { - m_dependentRequirers.remove(module); - } - - public synchronized List getDependents() - { - List dependents = new ArrayList - (m_dependentHosts.size() + m_dependentImporters.size() + m_dependentRequirers.size()); - dependents.addAll(m_dependentHosts); - dependents.addAll(m_dependentImporters); - dependents.addAll(m_dependentRequirers); - return dependents; - } - - public synchronized void close() - { - m_content.close(); - for (int i = 0; (m_contentPath != null) && (i < m_contentPath.length); i++) - { - m_contentPath[i].close(); - } - for (int i = 0; (m_fragmentContents != null) && (i < m_fragmentContents.length); i++) - { - m_fragmentContents[i].close(); - } - m_classLoader = null; - } + ((VirtualContentImpl) m_virtualContent).close(); + } public synchronized void setSecurityContext(Object securityContext) { @@ -1271,1011 +574,6 @@ public class ModuleImpl implements Modul return m_id; } - private synchronized ModuleClassLoader getClassLoader() - { - if (m_classLoader == null) - { - if (System.getSecurityManager() != null) - { - try - { - Constructor ctor = (Constructor) m_secureAction.getConstructor( - ModuleClassLoader.class, - new Class[] { ModuleImpl.class, ClassLoader.class }); - m_classLoader = (ModuleClassLoader) - m_secureAction.invoke(ctor, - new Object[] { this, determineParentClassLoader() }); - } - catch (Exception ex) - { - throw new RuntimeException("Unable to create module class loader: " - + ex.getMessage() + " [" + ex.getClass().getName() + "]"); - } - } - else - { - m_classLoader = new ModuleClassLoader(determineParentClassLoader()); - } - } - return m_classLoader; - } - - private ClassLoader determineParentClassLoader() - { - // Determine the class loader's parent based on the - // configuration property; use boot class loader by - // default. - String cfg = (String) m_configMap.get(Constants.FRAMEWORK_BUNDLE_PARENT); - cfg = (cfg == null) ? Constants.FRAMEWORK_BUNDLE_PARENT_BOOT : cfg; - final ClassLoader parent; - if (cfg.equalsIgnoreCase(Constants.FRAMEWORK_BUNDLE_PARENT_APP)) - { - parent = m_secureAction.getSystemClassLoader(); - } - else if (cfg.equalsIgnoreCase(Constants.FRAMEWORK_BUNDLE_PARENT_EXT)) - { - parent = m_secureAction.getSystemClassLoader().getParent(); - } - else if (cfg.equalsIgnoreCase(Constants.FRAMEWORK_BUNDLE_PARENT_FRAMEWORK)) - { - parent = ModuleImpl.class.getClassLoader(); - } - // On Android we cannot set the parent class loader to be null, so - // we special case that situation here and set it to the system - // class loader by default instead, which is not really spec. - else if (m_bootClassLoader == null) - { - parent = m_secureAction.getSystemClassLoader(); - } - else - { - parent = null; - } - return parent; - } - - private Object searchImports(String name, boolean isClass) - throws ClassNotFoundException, ResourceNotFoundException - { - // We delegate to the module's wires to find the class or resource. - List wires = getWires(); - for (int i = 0; (wires != null) && (i < wires.size()); i++) - { - // If we find the class or resource, then return it. - Object result = (isClass) - ? (Object) wires.get(i).getClass(name) - : (Object) wires.get(i).getResource(name); - if (result != null) - { - return result; - } - } - - return null; - } - - private Object searchDynamicImports( - final String name, String pkgName, final boolean isClass) - throws ClassNotFoundException, ResourceNotFoundException - { - // 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. - Wire wire = null; - try - { - wire = m_resolver.resolve(this, pkgName); - } - catch (ResolveException ex) - { - // Ignore this since it is likely normal. - } - - // If the dynamic import was successful, then this initial - // time we must directly return the result from dynamically - // created wire, but subsequent requests for classes/resources - // in the associated package will be processed as part of - // normal static imports. - if (wire != null) - { - // Return the class or resource. - return (isClass) - ? (Object) wire.getClass(name) - : (Object) wire.getResource(name); - } - - // If implicit boot delegation is enabled, then try to guess whether - // we should boot delegate. - if (m_implicitBootDelegation) - { - // At this point, the class/resource could not be found by the bundle's - // static or dynamic imports, nor its own content. Before we throw - // an exception, we will try to determine if the instigator of the - // class/resource load was a class from a bundle or not. This is necessary - // because the specification mandates that classes on the class path - // should be hidden (except for java.*), but it does allow for these - // classes/resources to be exposed by the system bundle as an export. - // However, in some situations classes on the class path make the faulty - // assumption that they can access everything on the class path from - // every other class loader that they come in contact with. This is - // not true if the class loader in question is from a bundle. Thus, - // this code tries to detect that situation. If the class instigating - // the load request was NOT from a bundle, then we will make the - // assumption that the caller actually wanted to use the parent class - // loader and we will delegate to it. If the class was - // from a bundle, then we will enforce strict class loading rules - // for the bundle and throw an exception. - - // Get the class context to see the classes on the stack. - final Class[] classes = m_sm.getClassContext(); - try - { - if (System.getSecurityManager() != null) - { - return AccessController - .doPrivileged(new PrivilegedExceptionAction() - { - public Object run() throws Exception - { - return doImplicitBootDelegation(classes, name, - isClass); - } - }); - } - else - { - return doImplicitBootDelegation(classes, name, isClass); - } - } - catch (PrivilegedActionException ex) - { - Exception cause = ex.getException(); - if (cause instanceof ClassNotFoundException) - { - throw (ClassNotFoundException) cause; - } - else - { - throw (ResourceNotFoundException) cause; - } - } - } - return null; - } - - private Object doImplicitBootDelegation(Class[] classes, String name, boolean isClass) - throws ClassNotFoundException, ResourceNotFoundException - { - // Start from 1 to skip security manager class. - for (int i = 1; i < classes.length; i++) - { - // Find the first class on the call stack that is not from - // the class loader that loaded the Felix classes or is not - // a class loader or class itself, because we want to ignore - // calls to ClassLoader.loadClass() and Class.forName() since - // we are trying to find out who instigated the class load. - // Also ignore inner classes of class loaders, since we can - // assume they are a class loader too. - - // TODO: FRAMEWORK - This check is a hack and we should see if we can think - // of another way to do it, since it won't necessarily work in all situations. - // Since Felix uses threads for changing the start level - // and refreshing packages, it is possible that there is no - // module classes on the call stack; therefore, as soon as we - // see Thread on the call stack we exit this loop. Other cases - // where modules actually use threads are not an issue because - // the module classes will be on the call stack before the - // Thread class. - if (Thread.class.equals(classes[i])) - { - break; - } - else if (isClassNotLoadedFromBundle(classes[i])) - { - // If the instigating class was not from a bundle, - // then delegate to the parent class loader; otherwise, - // break out of loop and return null. - boolean delegate = true; - ClassLoader last = null; - for (ClassLoader cl = classes[i].getClassLoader(); - (cl != null) && (last != cl); - cl = cl.getClass().getClassLoader()) - { - last = cl; - if (ModuleClassLoader.class.isInstance(cl)) - { - delegate = false; - break; - } - } - // Delegate to the parent class loader unless this call - // is due to outside code calling a method on the bundle - // interface (e.g., Bundle.loadClass()). - if (delegate && !Bundle.class.isAssignableFrom(classes[i - 1])) - { - try - { - // Return the class or resource from the parent class loader. - return (isClass) - ? (Object) this.getClass().getClassLoader().loadClass(name) - : (Object) this.getClass().getClassLoader().getResource(name); - } - catch (NoClassDefFoundError ex) - { - // Ignore, will return null - } - } - break; - } - } - - return null; - } - - private boolean isClassNotLoadedFromBundle(Class clazz) - { - // If this is an inner class, try to get the enclosing class - // because we can assume that inner classes of class loaders - // are really just the class loader and we should ignore them. - clazz = getEnclosingClass(clazz); - return (this.getClass().getClassLoader() != clazz.getClassLoader()) - && !ClassLoader.class.isAssignableFrom(clazz) - && !Class.class.equals(clazz) - && !Proxy.class.equals(clazz); - } - - private static Class getEnclosingClass(Class clazz) - { - // This code determines if the class is an inner class and if so - // returns the enclosing class. At one point in time this code used - // Class.getEnclosingClass() for JDKs > 1.5, but due to a bug in the - // JDK which caused invalid ClassCircularityErrors we had to remove it. - int idx = clazz.getName().lastIndexOf('$'); - if (idx > 0) - { - ClassLoader cl = (clazz.getClassLoader() != null) - ? clazz.getClassLoader() : ClassLoader.getSystemClassLoader(); - try - { - Class enclosing = cl.loadClass(clazz.getName().substring(0, idx)); - clazz = (enclosing != null) ? enclosing : clazz; - } - catch (Throwable t) - { - // Ignore all problems since we are trying to load a class - // inside the class loader and this can lead to - // ClassCircularityError, for example. - } - } - - return clazz; - } - - boolean shouldBootDelegate(String pkgName) - { - // Always boot delegate if the bundle has a configured - // boot class loader. - if (m_bootClassLoader != m_defBootClassLoader) - { - return true; - } - - boolean result = false; - - // Only consider delegation if we have a package name, since - // we don't want to promote the default package. The spec does - // not take a stand on this issue. - if (pkgName.length() > 0) - { - for (int i = 0; !result && (i < m_bootPkgs.length); i++) - { - // Check if the boot package is wildcarded. - // A wildcarded boot package will be in the form "foo.", - // so a matching subpackage will start with "foo.", e.g., - // "foo.bar". - if (m_bootPkgWildcards[i] && pkgName.startsWith(m_bootPkgs[i])) - { - return true; - } - // If not wildcarded, then check for an exact match. - else if (m_bootPkgs[i].equals(pkgName)) - { - return true; - } - } - } - - return result; - } - - ClassLoader getBootDelegationClassLoader() - { - // Get the appropriate class loader for delegation. - ClassLoader parent = (m_classLoader == null) - ? determineParentClassLoader() : m_classLoader.getParent(); - return (parent == null) ? m_bootClassLoader : parent; - } - - private static final Constructor m_dexFileClassConstructor; - private static final Method m_dexFileClassLoadDex; - private static final Method m_dexFileClassLoadClass; - - static - { - Constructor dexFileClassConstructor = null; - Method dexFileClassLoadDex = null; - Method dexFileClassLoadClass = null; - try - { - Class dexFileClass; - try - { - dexFileClass = Class.forName("dalvik.system.DexFile"); - } - catch (Exception ex) - { - dexFileClass = Class.forName("android.dalvik.DexFile"); - } - - try - { - dexFileClassLoadDex = dexFileClass.getMethod("loadDex", - new Class[]{String.class, String.class, Integer.TYPE}); - } - catch (Exception ex) - { - // Nothing we need to do - } - dexFileClassConstructor = dexFileClass.getConstructor( - new Class[] { java.io.File.class }); - dexFileClassLoadClass = dexFileClass.getMethod("loadClass", - new Class[] { String.class, ClassLoader.class }); - } - catch (Throwable ex) - { - dexFileClassConstructor = null; - dexFileClassLoadDex = null; - dexFileClassLoadClass = null; - } - m_dexFileClassConstructor = dexFileClassConstructor; - m_dexFileClassLoadDex= dexFileClassLoadDex; - m_dexFileClassLoadClass = dexFileClassLoadClass; - } - - public class ModuleClassLoader extends SecureClassLoader implements BundleReference - { - private final Map m_jarContentToDexFile; - private Object[][] m_cachedLibs = new Object[0][]; - private static final int LIBNAME_IDX = 0; - private static final int LIBPATH_IDX = 1; - - public ModuleClassLoader(ClassLoader parent) - { - super(parent); - if (m_dexFileClassLoadClass != null) - { - m_jarContentToDexFile = new HashMap(); - } - else - { - m_jarContentToDexFile = null; - } - } - - public Bundle getBundle() - { - return ModuleImpl.this.getBundle(); - } - - protected Class loadClass(String name, boolean resolve) - throws ClassNotFoundException - { - Class clazz = null; - - // Make sure the class was not already loaded. - synchronized (this) - { - clazz = findLoadedClass(name); - } - - if (clazz == null) - { - try - { - clazz = (Class) findClassOrResourceByDelegation(name, true); - } - catch (ResourceNotFoundException ex) - { - // This should never happen since we are asking for a class, - // so just ignore it. - } - catch (ClassNotFoundException cnfe) - { - ClassNotFoundException ex = cnfe; - String msg = name; - if (m_logger.getLogLevel() >= Logger.LOG_DEBUG) - { - msg = diagnoseClassLoadError(m_resolver, ModuleImpl.this, name); - ex = (msg != null) - ? new ClassNotFoundException(msg, cnfe) - : ex; - } - throw ex; - } - } - - // Resolve the class and return it. - if (resolve) - { - resolveClass(clazz); - } - return clazz; - } - - protected Class findClass(String name) throws ClassNotFoundException - { - Class clazz = null; - - // Search for class in module. - if (clazz == null) - { - String actual = name.replace('.', '/') + ".class"; - - byte[] bytes = null; - - // Check the module class path. - Content[] contentPath = getContentPath(); - Content content = null; - for (int i = 0; - (bytes == null) && - (i < contentPath.length); i++) - { - bytes = contentPath[i].getEntryAsBytes(actual); - content = contentPath[i]; - } - - if (bytes != null) - { - // Get package name. - String pkgName = Util.getClassPackage(name); - - // Before we actually attempt to define the class, grab - // the lock for this class loader and make sure than no - // other thread has defined this class in the meantime. - synchronized (this) - { - clazz = findLoadedClass(name); - - if (clazz == null) - { - int activationPolicy = - ((BundleImpl) getBundle()).isDeclaredActivationPolicyUsed() - ? ((BundleImpl) getBundle()).getCurrentModule().getDeclaredActivationPolicy() - : Module.EAGER_ACTIVATION; - - // If the module is using deferred activation, then if - // we load this class from this module we need to activate - // the module before returning the class. We will short - // circuit the trigger matching if the trigger is already - // tripped. - boolean isTriggerClass = m_isActivationTriggered - ? false : isActivationTrigger(pkgName); - if (!m_isActivationTriggered - && isTriggerClass - && (activationPolicy == Module.LAZY_ACTIVATION) - && (getBundle().getState() == Bundle.STARTING)) - { - List deferredList = (List) m_deferredActivation.get(); - if (deferredList == null) - { - deferredList = new ArrayList(); - m_deferredActivation.set(deferredList); - } - deferredList.add(new Object[] { name, getBundle() }); - } - // We need to try to define a Package object for the class - // before we call defineClass() if we haven't already - // created it. - if (pkgName.length() > 0) - { - if (getPackage(pkgName) == null) - { - Object[] params = definePackage(pkgName); - if (params != null) - { - definePackage( - pkgName, - (String) params[0], - (String) params[1], - (String) params[2], - (String) params[3], - (String) params[4], - (String) params[5], - null); - } - else - { - definePackage(pkgName, null, null, - null, null, null, null, null); - } - } - } - - // If we can load the class from a dex file do so - if (content instanceof JarContent) - { - try - { - clazz = getDexFileClass((JarContent) content, name, this); - } - catch (Exception ex) - { - // Looks like we can't - } - } - - if (clazz == null) - { - // If we have a security context, then use it to - // define the class with it for security purposes, - // otherwise define the class without a protection domain. - if (m_protectionDomain != null) - { - clazz = defineClass(name, bytes, 0, bytes.length, - m_protectionDomain); - } - else - { - clazz = defineClass(name, bytes, 0, bytes.length); - } - } - - // At this point if we have a trigger class, then the deferred - // activation trigger has tripped. - if (!m_isActivationTriggered && isTriggerClass && (clazz != null)) - { - m_isActivationTriggered = true; - } - } - } - - // Perform deferred activation without holding the class loader lock, - // if the class we are returning is the instigating class. - List deferredList = (List) m_deferredActivation.get(); - if ((deferredList != null) - && (deferredList.size() > 0) - && ((Object[]) deferredList.get(0))[0].equals(name)) - { - for (int i = deferredList.size() - 1; i >= 0; i--) - { - try - { - ((BundleImpl) ((Object[]) deferredList.get(i))[1]).getFramework().activateBundle( - (BundleImpl) ((Object[]) deferredList.get(i))[1], true); - } - catch (BundleException ex) - { - ex.printStackTrace(); - } - } - deferredList.clear(); - } - } - } - - return clazz; - } - - private Object[] definePackage(String pkgName) - { - String spectitle = (String) m_headerMap.get("Specification-Title"); - String specversion = (String) m_headerMap.get("Specification-Version"); - String specvendor = (String) m_headerMap.get("Specification-Vendor"); - String impltitle = (String) m_headerMap.get("Implementation-Title"); - String implversion = (String) m_headerMap.get("Implementation-Version"); - String implvendor = (String) m_headerMap.get("Implementation-Vendor"); - if ((spectitle != null) - || (specversion != null) - || (specvendor != null) - || (impltitle != null) - || (implversion != null) - || (implvendor != null)) - { - return new Object[] { - spectitle, specversion, specvendor, impltitle, implversion, implvendor - }; - } - return null; - } - - private Class getDexFileClass(JarContent content, String name, ClassLoader loader) - throws Exception - { - if (m_jarContentToDexFile == null) - { - return null; - } - - Object dexFile = null; - - if (!m_jarContentToDexFile.containsKey(content)) - { - try - { - if (m_dexFileClassLoadDex != null) - { - dexFile = m_dexFileClassLoadDex.invoke(null, - new Object[]{content.getFile().getAbsolutePath(), - content.getFile().getAbsolutePath() + ".dex", new Integer(0)}); - } - else - { - dexFile = m_dexFileClassConstructor.newInstance( - new Object[] { content.getFile() }); - } - } - finally - { - m_jarContentToDexFile.put(content, dexFile); - } - } - else - { - dexFile = m_jarContentToDexFile.get(content); - } - - if (dexFile != null) - { - return (Class) m_dexFileClassLoadClass.invoke(dexFile, - new Object[] { name.replace('.','/'), loader }); - } - return null; - } - - public URL getResource(String name) - { - return ModuleImpl.this.getResourceByDelegation(name); - } - - protected URL findResource(String name) - { - return getResourceLocal(name); - } - - // The findResources() method should only look at the module itself, but - // instead it tries to delegate because in Java version prior to 1.5 the - // getResources() method was final and could not be overridden. We should - // override getResources() like getResource() to make it delegate, but we - // can't. As a workaround, we make findResources() delegate instead. - protected Enumeration findResources(String name) - { - return getResourcesByDelegation(name); - } - - protected String findLibrary(String name) - { - // Remove leading slash, if present. - if (name.startsWith("/")) - { - name = name.substring(1); - } - - String result = null; - // CONCURRENCY: In the long run, we might want to break this - // sync block in two to avoid manipulating the cache while - // holding the lock, but for now we will do it the simple way. - synchronized (this) - { - // Check to make sure we haven't already found this library. - for (int i = 0; (result == null) && (i < m_cachedLibs.length); i++) - { - if (m_cachedLibs[i][LIBNAME_IDX].equals(name)) - { - result = (String) m_cachedLibs[i][LIBPATH_IDX]; - } - } - - // If we don't have a cached result, see if we have a matching - // native library. - if (result == null) - { - List libs = getNativeLibraries(); - for (int libIdx = 0; (libs != null) && (libIdx < libs.size()); libIdx++) - { - if (libs.get(libIdx).match(m_configMap, name)) - { - // Search bundle content first for native library. - result = getContent().getEntryAsNativeLibrary( - libs.get(libIdx).getEntryName()); - // If not found, then search fragments in order. - for (int i = 0; - (result == null) && (m_fragmentContents != null) - && (i < m_fragmentContents.length); - i++) - { - result = m_fragmentContents[i].getEntryAsNativeLibrary( - libs.get(libIdx).getEntryName()); - } - } - } - - // Remember the result for future requests. - if (result != null) - { - Object[][] tmp = new Object[m_cachedLibs.length + 1][]; - System.arraycopy(m_cachedLibs, 0, tmp, 0, m_cachedLibs.length); - tmp[m_cachedLibs.length] = new Object[] { name, result }; - m_cachedLibs = tmp; - } - } - } - - return result; - } - - public String toString() - { - return ModuleImpl.this.toString(); - } - } - - private static String diagnoseClassLoadError( - FelixResolver resolver, ModuleImpl module, String name) - { - // We will try to do some diagnostics here to help the developer - // deal with this exception. - - // Get package name. - String pkgName = Util.getClassPackage(name); - if (pkgName.length() == 0) - { - return null; - } - - // First, get the bundle string of the module doing the class loader. - String importer = module.getBundle().toString(); - - // Next, check to see if the module imports the package. - List wires = module.getWires(); - for (int i = 0; (wires != null) && (i < wires.size()); i++) - { - if (wires.get(i).getCapability().getNamespace().equals(Capability.PACKAGE_NAMESPACE) && - wires.get(i).getCapability().getAttribute(Capability.PACKAGE_ATTR).getValue().equals(pkgName)) - { - String exporter = wires.get(i).getExporter().getBundle().toString(); - - StringBuffer sb = new StringBuffer("*** Package '"); - sb.append(pkgName); - sb.append("' is imported by bundle "); - sb.append(importer); - sb.append(" from bundle "); - sb.append(exporter); - sb.append(", but the exported package from bundle "); - sb.append(exporter); - sb.append(" does not contain the requested class '"); - sb.append(name); - sb.append("'. Please verify that the class name is correct in the importing bundle "); - sb.append(importer); - sb.append(" and/or that the exported package is correctly bundled in "); - sb.append(exporter); - sb.append(". ***"); - - return sb.toString(); - } - } - - // Next, check to see if the package was optionally imported and - // whether or not there is an exporter available. - List reqs = module.getRequirements(); -/* -* TODO: RB - Fix diagnostic message for optional imports. - for (int i = 0; (reqs != null) && (i < reqs.length); i++) - { - if (reqs[i].getName().equals(pkgName) && reqs[i].isOptional()) - { - // Try to see if there is an exporter available. - IModule[] exporters = getResolvedExporters(reqs[i], true); - exporters = (exporters.length == 0) - ? getUnresolvedExporters(reqs[i], true) : exporters; - - // An exporter might be available, but it may have attributes - // that do not match the importer's required attributes, so - // check that case by simply looking for an exporter of the - // desired package without any attributes. - if (exporters.length == 0) - { - IRequirement pkgReq = new Requirement( - ICapability.PACKAGE_NAMESPACE, "(package=" + pkgName + ")"); - exporters = getResolvedExporters(pkgReq, true); - exporters = (exporters.length == 0) - ? getUnresolvedExporters(pkgReq, true) : exporters; - } - - long expId = (exporters.length == 0) - ? -1 : Util.getBundleIdFromModuleId(exporters[0].getId()); - - StringBuffer sb = new StringBuffer("*** Class '"); - sb.append(name); - sb.append("' was not found, but this is likely normal since package '"); - sb.append(pkgName); - sb.append("' is optionally imported by bundle "); - sb.append(impId); - sb.append("."); - if (exporters.length > 0) - { - sb.append(" However, bundle "); - sb.append(expId); - if (reqs[i].isSatisfied( - Util.getExportPackage(exporters[0], reqs[i].getName()))) - { - sb.append(" does export this package. Bundle "); - sb.append(expId); - sb.append(" must be installed before bundle "); - sb.append(impId); - sb.append(" is resolved or else the optional import will be ignored."); - } - else - { - sb.append(" does export this package with attributes that do not match."); - } - } - sb.append(" ***"); - - return sb.toString(); - } - } -*/ - // Next, check to see if the package is dynamically imported by the module. - if (resolver.isAllowedDynamicImport(module, pkgName)) - { - // Try to see if there is an exporter available. - List dirs = Collections.EMPTY_LIST; - List attrs = new ArrayList(1); - attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false)); - Requirement req = new RequirementImpl( - module, Capability.PACKAGE_NAMESPACE, dirs, attrs); - Set exporters = resolver.getCandidates(module, req, false); - - Wire wire = null; - try - { - wire = resolver.resolve(module, pkgName); - } - catch (Exception ex) - { - wire = null; - } - - String exporter = (exporters.size() == 0) - ? null : exporters.iterator().next().getModule().getBundle().toString(); - - StringBuffer sb = new StringBuffer("*** Class '"); - sb.append(name); - sb.append("' was not found, but this is likely normal since package '"); - sb.append(pkgName); - sb.append("' is dynamically imported by bundle "); - sb.append(importer); - sb.append("."); - if ((exporters.size() > 0) && (wire == null)) - { - sb.append(" However, bundle "); - sb.append(exporter); - sb.append(" does export this package with attributes that do not match."); - } - sb.append(" ***"); - - return sb.toString(); - } - - // Next, check to see if there are any exporters for the package at all. - List dirs = Collections.EMPTY_LIST; - List attrs = new ArrayList(1); - attrs.add(new Attribute(Capability.PACKAGE_ATTR, pkgName, false)); - Requirement req = new RequirementImpl( - module, Capability.PACKAGE_NAMESPACE, dirs, attrs); - Set exports = resolver.getCandidates(module, req, false); - if (exports.size() > 0) - { - boolean classpath = false; - try - { - ModuleClassLoader.class.getClassLoader().loadClass(name); - classpath = true; - } - catch (NoClassDefFoundError err) - { - // Ignore - } - catch (Exception ex) - { - // Ignore - } - - String exporter = exports.iterator().next().getModule().getBundle().toString(); - - StringBuffer sb = new StringBuffer("*** Class '"); - sb.append(name); - sb.append("' was not found because bundle "); - sb.append(importer); - sb.append(" does not import '"); - sb.append(pkgName); - sb.append("' even though bundle "); - sb.append(exporter); - sb.append(" does export it."); - if (classpath) - { - sb.append(" Additionally, the class is also available from the system class loader. There are two fixes: 1) Add an import for '"); - sb.append(pkgName); - sb.append("' to bundle "); - sb.append(importer); - sb.append("; imports are necessary for each class directly touched by bundle code or indirectly touched, such as super classes if their methods are used. "); - sb.append("2) Add package '"); - sb.append(pkgName); - sb.append("' to the '"); - sb.append(Constants.FRAMEWORK_BOOTDELEGATION); - sb.append("' property; a library or VM bug can cause classes to be loaded by the wrong class loader. The first approach is preferable for preserving modularity."); - } - else - { - sb.append(" To resolve this issue, add an import for '"); - sb.append(pkgName); - sb.append("' to bundle "); - sb.append(importer); - sb.append("."); - } - sb.append(" ***"); - - return sb.toString(); - } - - // Next, try to see if the class is available from the system - // class loader. - try - { - ModuleClassLoader.class.getClassLoader().loadClass(name); - - StringBuffer sb = new StringBuffer("*** Package '"); - sb.append(pkgName); - sb.append("' is not imported by bundle "); - sb.append(importer); - sb.append(", nor is there any bundle that exports package '"); - sb.append(pkgName); - sb.append("'. However, the class '"); - sb.append(name); - sb.append("' is available from the system class loader. There are two fixes: 1) Add package '"); - sb.append(pkgName); - sb.append("' to the '"); - sb.append(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA); - sb.append("' property and modify bundle "); - sb.append(importer); - sb.append(" to import this package; this causes the system bundle to export class path packages. 2) Add package '"); - sb.append(pkgName); - sb.append("' to the '"); - sb.append(Constants.FRAMEWORK_BOOTDELEGATION); - sb.append("' property; a library or VM bug can cause classes to be loaded by the wrong class loader. The first approach is preferable for preserving modularity."); - sb.append(" ***"); - - return sb.toString(); - } - catch (Exception ex2) - { - } - - // Finally, if there are no imports or exports for the package - // and it is not available on the system class path, simply - // log a message saying so. - StringBuffer sb = new StringBuffer("*** Class '"); - sb.append(name); - sb.append("' was not found. Bundle "); - sb.append(importer); - sb.append(" does not import package '"); - sb.append(pkgName); - sb.append("', nor is the package exported by any other bundle or available from the system class loader."); - sb.append(" ***"); - - return sb.toString(); - } - static class FragmentRequirement implements Requirement { private final Module m_owner; Modified: felix/sandbox/rickhall/framework-vb/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java URL: http://svn.apache.org/viewvc/felix/sandbox/rickhall/framework-vb/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java?rev=952424&r1=952423&r2=952424&view=diff ============================================================================== --- felix/sandbox/rickhall/framework-vb/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java (original) +++ felix/sandbox/rickhall/framework-vb/src/main/java/org/apache/felix/framework/URLHandlersBundleURLConnection.java Mon Jun 7 20:40:20 2010 @@ -103,7 +103,8 @@ class URLHandlersBundleURLConnection ext { m_classPathIdx = 0; } - if (!modules.get(revision).hasInputStream(m_classPathIdx, url.getPath())) + if (!((VirtualContentImpl) modules.get(revision).getVirtualContent()) + .hasInputStream(m_classPathIdx, url.getPath())) { URL newurl = modules.get(revision).getResourceByDelegation(url.getPath()); if (newurl == null) @@ -122,7 +123,8 @@ class URLHandlersBundleURLConnection ext { throw new IOException("Resource does not exist: " + url); } - m_is = m_targetModule.getInputStream(m_classPathIdx, url.getPath()); + m_is = ((VirtualContentImpl) m_targetModule.getVirtualContent()) + .getInputStream(m_classPathIdx, url.getPath()); m_contentLength = (m_is == null) ? 0 : m_is.available(); m_contentType = URLConnection.guessContentTypeFromName(url.getFile()); connected = true;