Copyright (c) 2003, 2014 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2003, 2014 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.osgi.internal.loader.sources; import java.io.IOException; import java.net.URL; import java.util.Collection; import java.util.Enumeration; import org.eclipse.osgi.container.ModuleRevision; import org.eclipse.osgi.container.ModuleWiring; import org.eclipse.osgi.internal.framework.EquinoxBundle; import org.eclipse.osgi.internal.framework.EquinoxContainer; import org.eclipse.osgi.internal.loader.BundleLoader; import org.eclipse.osgi.internal.loader.SystemBundleLoader; import org.osgi.framework.Bundle; import org.osgi.framework.ServiceFactory; import org.osgi.service.packageadmin.PackageAdmin; public abstract class PackageSource { protected final String id; public PackageSource(String id) { // others depend on the id being interned; see SingleSourcePackage.equals this.id = id.intern(); } public String getId() { return id; } public abstract SingleSourcePackage[] getSuppliers(); public boolean compare(PackageSource other) { return id.equals(other.getId()); } @Override public int hashCode() { return id.hashCode(); } public boolean isNullSource() { return false; } public abstract Class<?> loadClass(String name) throws ClassNotFoundException; public abstract URL getResource(String name); public abstract Enumeration<URL> getResources(String name) throws IOException; //TODO See how this relates with FilteredSourcePackage. Overwriting or doing a double dispatch might be good. // This is intentionally lenient; we don't force all suppliers to match (only one) // it is better to get class cast exceptions in split package cases than miss an event public boolean hasCommonSource(PackageSource other) { if (other == null) return false; if (this == other) return true; SingleSourcePackage[] suppliers1 = getSuppliers(); SingleSourcePackage[] suppliers2 = other.getSuppliers(); if (suppliers1 == null || suppliers2 == null) return false; // This will return true if the specified source has at least one // of the suppliers of this source. for (SingleSourcePackage supplier1 : suppliers1) { for (SingleSourcePackage supplier2 : suppliers2) { if (supplier2.equals(supplier1)) { return true; } } } return false; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append(id).append(" -> "); //$NON-NLS-1$ SingleSourcePackage[] suppliers = getSuppliers(); if (suppliers == null) { return builder.append(String.valueOf(null)).toString(); } builder.append('['); for (int i = 0; i < suppliers.length; i++) { if (i > 0) { builder.append(','); } builder.append(suppliers[i].getLoader()); } builder.append(']'); return builder.toString(); } public abstract Collection<String> listResources(String path, String filePattern);
Used by ServiceReferenceImpl for isAssignableTo
Params:
  • registrant – Bundle registering service
  • client – Bundle desiring to use service
  • className – class name to use
  • serviceClass – class of original service object
  • container – the equinox container
Returns:true if assignable given package wiring
/** * Used by ServiceReferenceImpl for isAssignableTo * @param registrant Bundle registering service * @param client Bundle desiring to use service * @param className class name to use * @param serviceClass class of original service object * @param container the equinox container * @return true if assignable given package wiring */
public static boolean isServiceAssignableTo(Bundle registrant, Bundle client, String className, Class<?> serviceClass, EquinoxContainer container) { // 1) if the registrant == client always return true if (registrant == client) { return true; } // 2) get the package name from the specified className String pkgName = BundleLoader.getPackageName(className); if (pkgName.startsWith("java.")) //$NON-NLS-1$ return true; BundleLoader producerBL = getBundleLoader(registrant); if (producerBL == null) return false; BundleLoader consumerBL = getBundleLoader(client); if (consumerBL == null) return false; // 3) for the specified bundle, find the wiring for the package. If no wiring is found return true PackageSource consumerSource = consumerBL.getPackageSource(pkgName); if (consumerSource == null) return true; // work around the issue when the package is in the EE and we delegate to boot for that package if (container.isBootDelegationPackage(pkgName)) { Bundle systemBundle = container.getStorage().getModuleContainer().getModule(0).getBundle(); SystemBundleLoader systemLoader = (SystemBundleLoader) getBundleLoader(systemBundle); if (systemLoader.isExportedPackage(pkgName)) { return true; // in this case we have a common source from the EE } } // 4) For the registrant bundle, find the wiring for the package. PackageSource producerSource = producerBL.getPackageSource(pkgName); if (producerSource == null) { if (serviceClass != null && ServiceFactory.class.isAssignableFrom(serviceClass)) { @SuppressWarnings("deprecation") Bundle bundle = container.getPackageAdmin().getBundle(serviceClass); if (bundle != null && bundle != registrant) // in this case we have a wacky ServiceFactory that is doing something we cannot // verify if it is correct. Instead of failing we allow the assignment and hope for the best // bug 326918 return true; } // 5) If no wiring is found for the registrant bundle then find the wiring for the classloader of the service object. If no wiring is found return false. producerSource = getPackageSource(serviceClass, pkgName, container.getPackageAdmin()); if (producerSource == null) return false; } // 6) If the two wirings found are equal then return true; otherwise return false. return producerSource.hasCommonSource(consumerSource); } private static PackageSource getPackageSource(Class<?> serviceClass, String pkgName, @SuppressWarnings("deprecation") PackageAdmin packageAdmin) { if (serviceClass == null) return null; @SuppressWarnings("deprecation") Bundle serviceBundle = packageAdmin.getBundle(serviceClass); if (serviceBundle == null) return null; BundleLoader producerBL = getBundleLoader(serviceBundle); if (producerBL == null) return null; PackageSource producerSource = producerBL.getPackageSource(pkgName); if (producerSource != null) return producerSource; // try the interfaces Class<?>[] interfaces = serviceClass.getInterfaces(); // note that getInterfaces never returns null for (Class<?> intf : interfaces) { producerSource = getPackageSource(intf, pkgName, packageAdmin); if (producerSource != null) return producerSource; } // try super class return getPackageSource(serviceClass.getSuperclass(), pkgName, packageAdmin); } private static BundleLoader getBundleLoader(Bundle bundle) { ModuleRevision producer = ((EquinoxBundle) bundle).getModule().getCurrentRevision(); ModuleWiring producerWiring = producer.getWiring(); return producerWiring == null ? null : (BundleLoader) producerWiring.getModuleLoader(); } }