| /******************************************************************************* |
| * Copyright (c) 2003, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.osgi.framework.internal.core; |
| |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.ServiceReference; |
| |
| /** |
| * A reference to a service. |
| * |
| * The framework returns ServiceReference objects from the |
| * {@link BundleContextImpl#getServiceReference BundleContext.getServiceReference} and |
| * {@link BundleContextImpl#getServiceReferences BundleContext.getServiceReferences} methods. |
| * <p>A ServiceReference may be shared between bundles and |
| * can be used to examine the properties of the service and to |
| * get the service object |
| * (See {@link BundleContextImpl#getService BundleContext.getService}). |
| * <p>A registered service <i>may</i> have multiple, distinct ServiceReference |
| * objects which refer to it. |
| * However these ServiceReference objects will have |
| * the same <code>hashCode</code> and the <code>equals</code> method |
| * will return <code>true</code> when compared. |
| */ |
| |
| public class ServiceReferenceImpl implements ServiceReference, Comparable { |
| /** Registered Service object. */ |
| protected ServiceRegistrationImpl registration; |
| |
| /** |
| * Construct a reference. |
| * |
| */ |
| protected ServiceReferenceImpl(ServiceRegistrationImpl registration) { |
| this.registration = registration; |
| } |
| |
| /** |
| * Get the value of a service's property. |
| * |
| * <p>This method will continue to return property values after the |
| * service has been unregistered. This is so that references to |
| * unregistered service can be interrogated. |
| * (For example: ServiceReference objects stored in the log.) |
| * |
| * @param key Name of the property. |
| * @return Value of the property or <code>null</code> if there is |
| * no property by that name. |
| */ |
| public Object getProperty(String key) { |
| return (registration.getProperty(key)); |
| } |
| |
| /** |
| * Get the list of key names for the service's properties. |
| * |
| * <p>This method will continue to return the keys after the |
| * service has been unregistered. This is so that references to |
| * unregistered service can be interrogated. |
| * (For example: ServiceReference objects stored in the log.) |
| * |
| * @return The list of property key names. |
| */ |
| public String[] getPropertyKeys() { |
| return (registration.getPropertyKeys()); |
| } |
| |
| /** |
| * Return the bundle which registered the service. |
| * |
| * <p>This method will always return <code>null</code> when the |
| * service has been unregistered. This can be used to |
| * determine if the service has been unregistered. |
| * |
| * @return The bundle which registered the service. |
| */ |
| public org.osgi.framework.Bundle getBundle() { |
| return (registration.getBundle()); |
| } |
| |
| /** |
| * Return the list of bundles which are using the service. |
| * |
| * <p>This method will always return <code>null</code> when the |
| * service has been unregistered. |
| * |
| * @return The array of bundles using the service or null if |
| * no bundles are using the service. |
| * @see BundleContextImpl#getService |
| */ |
| public org.osgi.framework.Bundle[] getUsingBundles() { |
| return (registration.getUsingBundles()); |
| } |
| |
| /** |
| * Return the classes under which the referenced service was registered. |
| * |
| * @return array of class names. |
| */ |
| protected String[] getClasses() { |
| return (registration.clazzes); |
| } |
| |
| /** |
| * Return the serviceid of the ServiceRegistration. |
| * |
| * @return service.id of the service |
| */ |
| protected long getId() { |
| return (registration.serviceid); |
| } |
| |
| /** |
| * Return the serviceranking of the ServiceRegistration. |
| * |
| * @return service.ranking of the service |
| */ |
| protected int getRanking() { |
| return (registration.serviceranking); |
| } |
| |
| /** |
| * Returns a hash code value for the object. |
| * |
| * @return a hash code value for this object. |
| */ |
| public int hashCode() { |
| return (registration.hashCode()); |
| } |
| |
| /** |
| * Indicates whether some other object is "equal to" this one. |
| * |
| * @param obj the reference object with which to compare. |
| * @return <code>true</code> if this object is the same as the obj |
| * argument; <code>false</code> otherwise. |
| */ |
| public boolean equals(Object obj) { |
| if (obj == this) { |
| return (true); |
| } |
| |
| if (!(obj instanceof ServiceReferenceImpl)) { |
| return (false); |
| } |
| |
| ServiceReferenceImpl other = (ServiceReferenceImpl) obj; |
| |
| return (registration == other.registration); |
| } |
| |
| /** |
| * Return a string representation of this reference. |
| * |
| * @return String |
| */ |
| public String toString() { |
| return (registration.toString()); |
| } |
| |
| /** |
| * |
| * Compares two service objects and returns an indication as to which is higher ranked |
| * based on service ranking and service_ID. |
| * |
| * The service with the higher service ranking (as specified in its service.ranking property) |
| * is defined to be higher ranked. |
| * |
| * If there is a tie in ranking, the service with the lowest |
| * service ID (as specified in its service.id property); that is, |
| * the service that was registered first is returned. |
| * |
| * This is the same algorithm used by BundleContext.getServiceReference. |
| * |
| * @return int |
| * int = 0 if this object's ranking and |
| * service id are equivalent |
| * |
| * int < 0 if this object's ranking is lower |
| * than the argument's ranking or if the |
| * rankings are equal, this object's service |
| * id is greater than the argument's service |
| * id. |
| * |
| * int > 0 if this object's ranking is higher |
| * than than the argument's ranking or if the |
| * rankings are equal, this object's service |
| * id is less than the argument's service id. |
| * |
| * |
| * @param object |
| * an object to compare the receiver to |
| * @exception ClassCastException |
| * if the argument can not be converted |
| * into something comparable with the |
| * receiver. |
| */ |
| public int compareTo(Object object) { |
| ServiceReferenceImpl other = (ServiceReferenceImpl) object; |
| |
| int compare = this.getRanking() - other.getRanking(); |
| |
| if (compare == 0) /* rankings are equal */{ /* check service id */ |
| return (int) (other.getId() - this.getId()); |
| } |
| |
| return compare; |
| } |
| |
| public boolean isAssignableTo(Bundle bundle, String className) { |
| AbstractBundle consumer = (AbstractBundle) bundle; |
| // always return false for fragments |
| if (consumer.isFragment()) |
| return false; |
| BundleHost producer = (BundleHost) registration.bundle; |
| // 1) if the registrant == consumer always return true |
| if (consumer == producer) |
| 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 = producer.getBundleLoader(); |
| if (producerBL == null) |
| return false; |
| BundleLoader consumerBL = consumer.getBundleLoader(); |
| 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 (producerBL.isBootDelegationPackage(pkgName)) { |
| SystemBundleLoader systemLoader = (SystemBundleLoader) registration.framework.systemBundle.getBundleLoader(); |
| if (systemLoader.isEEPackage(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) { |
| // 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(registration.service.getClass(), pkgName); |
| if (producerSource == null) |
| return false; |
| } |
| // 6) If the two wirings found are equal then return true; otherwise return false. |
| return producerSource.hasCommonSource(consumerSource); |
| } |
| |
| private PackageSource getPackageSource(Class serviceClass, String pkgName) { |
| if (serviceClass == null) |
| return null; |
| AbstractBundle serviceBundle = (AbstractBundle) registration.framework.packageAdmin.getBundle(serviceClass); |
| if (serviceBundle == null) |
| return null; |
| BundleLoader producerBL = serviceBundle.getBundleLoader(); |
| 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 (int i = 0; i < interfaces.length; i++) { |
| producerSource = getPackageSource(interfaces[i], pkgName); |
| if (producerSource != null) |
| return producerSource; |
| } |
| // try super class |
| return getPackageSource(serviceClass.getSuperclass(), pkgName); |
| } |
| } |