KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > osgi > framework > internal > core > BundleContextImpl


1 /*******************************************************************************
2  * Copyright (c) 2003, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.osgi.framework.internal.core;
13
14 import java.io.File JavaDoc;
15 import java.io.InputStream JavaDoc;
16 import java.security.*;
17 import java.util.*;
18 import org.eclipse.osgi.event.BatchBundleListener;
19 import org.eclipse.osgi.framework.debug.Debug;
20 import org.eclipse.osgi.framework.eventmgr.EventDispatcher;
21 import org.eclipse.osgi.framework.eventmgr.EventListeners;
22 import org.eclipse.osgi.internal.profile.Profile;
23 import org.eclipse.osgi.util.NLS;
24 import org.osgi.framework.*;
25
26 /**
27  * Bundle's execution context.
28  *
29  * This object is given out to bundles and wraps the internal
30  * BundleContext object. It is destroyed when a bundle is stopped.
31  */

32
33 public class BundleContextImpl implements BundleContext, EventDispatcher {
34     public static final String JavaDoc PROP_SCOPE_SERVICE_EVENTS = "osgi.scopeServiceEvents"; //$NON-NLS-1$
35
public static final boolean scopeEvents = Boolean.valueOf(FrameworkProperties.getProperty(PROP_SCOPE_SERVICE_EVENTS, "true")).booleanValue(); //$NON-NLS-1$
36
/** true if the bundle context is still valid */
37     private boolean valid;
38
39     /** Bundle object this context is associated with. */
40     // This slot is accessed directly by the Framework instead of using
41
// the getBundle() method because the Framework needs access to the bundle
42
// even when the context is invalid while the close method is being called.
43
protected BundleHost bundle;
44
45     /** Internal framework object. */
46     protected Framework framework;
47
48     /** Services that bundle has used. Key is ServiceReference,
49      Value is ServiceUse */

50     protected Hashtable servicesInUse;
51
52     /** Listener list for bundle's BundleListeners */
53     protected EventListeners bundleEvent;
54
55     /** Listener list for bundle's SynchronousBundleListeners */
56     protected EventListeners bundleEventSync;
57
58     /** Listener list for bundle's ServiceListeners */
59     protected EventListeners serviceEvent;
60
61     /** Listener list for bundle's FrameworkListeners */
62     protected EventListeners frameworkEvent;
63
64     /** The current instantiation of the activator. */
65     protected BundleActivator activator;
66
67     /** private object for locking */
68     protected Object JavaDoc contextLock = new Object JavaDoc();
69
70     /**
71      * Construct a BundleContext which wrappers the framework for a
72      * bundle
73      *
74      * @param bundle The bundle we are wrapping.
75      */

76     protected BundleContextImpl(BundleHost bundle) {
77         this.bundle = bundle;
78         valid = true;
79         framework = bundle.framework;
80         bundleEvent = null;
81         bundleEventSync = null;
82         serviceEvent = null;
83         frameworkEvent = null;
84         servicesInUse = null;
85         activator = null;
86     }
87
88     /**
89      * Destroy the wrapper. This is called when the bundle is stopped.
90      *
91      */

92     protected void close() {
93         valid = false; /* invalidate context */
94
95         synchronized (framework.serviceEvent) {
96             if (serviceEvent != null) {
97                 framework.serviceEvent.removeListener(this);
98                 serviceEvent = null;
99             }
100         }
101         synchronized (framework.frameworkEvent) {
102             if (frameworkEvent != null) {
103                 framework.frameworkEvent.removeListener(this);
104                 frameworkEvent = null;
105             }
106         }
107         synchronized (framework.bundleEvent) {
108             if (bundleEvent != null) {
109                 framework.bundleEvent.removeListener(this);
110                 bundleEvent = null;
111             }
112         }
113         synchronized (framework.bundleEventSync) {
114             if (bundleEventSync != null) {
115                 framework.bundleEventSync.removeListener(this);
116                 bundleEventSync = null;
117             }
118         }
119
120         /* service's registered by the bundle, if any, are unregistered. */
121         ServiceReference[] publishedReferences = null;
122         synchronized (framework.serviceRegistry) {
123             publishedReferences = framework.serviceRegistry.lookupServiceReferences(this);
124         }
125
126         if (publishedReferences != null) {
127             for (int i = 0; i < publishedReferences.length; i++) {
128                 try {
129                     ((ServiceReferenceImpl) publishedReferences[i]).registration.unregister();
130                 } catch (IllegalStateException JavaDoc e) {
131                     /* already unregistered */
132                 }
133             }
134         }
135
136         /* service's used by the bundle, if any, are released. */
137         if (servicesInUse != null) {
138             int usedSize;
139             ServiceReference[] usedRefs = null;
140
141             synchronized (servicesInUse) {
142                 usedSize = servicesInUse.size();
143
144                 if (usedSize > 0) {
145                     if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
146                         Debug.println("Releasing services"); //$NON-NLS-1$
147
}
148
149                     usedRefs = new ServiceReference[usedSize];
150
151                     Enumeration refsEnum = servicesInUse.keys();
152                     for (int i = 0; i < usedSize; i++) {
153                         usedRefs[i] = (ServiceReference) refsEnum.nextElement();
154                     }
155                 }
156             }
157
158             for (int i = 0; i < usedSize; i++) {
159                 ((ServiceReferenceImpl) usedRefs[i]).registration.releaseService(this);
160             }
161
162             servicesInUse = null;
163         }
164
165         bundle = null;
166     }
167
168     /**
169      * Retrieve the value of the named environment property.
170      *
171      * @param key The name of the requested property.
172      * @return The value of the requested property, or <code>null</code> if
173      * the property is undefined.
174      */

175     public String JavaDoc getProperty(String JavaDoc key) {
176         SecurityManager JavaDoc sm = System.getSecurityManager();
177
178         if (sm != null) {
179             sm.checkPropertyAccess(key);
180         }
181
182         return (framework.getProperty(key));
183     }
184
185     /**
186      * Retrieve the Bundle object for the context bundle.
187      *
188      * @return The context bundle's Bundle object.
189      */

190     public org.osgi.framework.Bundle getBundle() {
191         checkValid();
192
193         return (bundle);
194     }
195
196     /**
197      * Install a bundle from a location.
198      *
199      * The bundle is obtained from the location
200      * parameter as interpreted by the framework
201      * in an implementation dependent way. Typically, location
202      * will most likely be a URL.
203      *
204      * @param location The location identifier of the bundle to install.
205      * @return The Bundle object of the installed bundle.
206      */

207     public org.osgi.framework.Bundle installBundle(String JavaDoc location) throws BundleException {
208         checkValid();
209         //note AdminPermission is checked after bundle is loaded
210
return framework.installBundle(location);
211     }
212
213     /**
214      * Install a bundle from an InputStream.
215      *
216      * <p>This method performs all the steps listed in
217      * {@link #installBundle(java.lang.String)}, except the
218      * bundle's content will be read from the InputStream.
219      * The location identifier specified will be used
220      * as the identity of the bundle.
221      *
222      * @param location The location identifier of the bundle to install.
223      * @param in The InputStream from which the bundle will be read.
224      * @return The Bundle of the installed bundle.
225      */

226     public org.osgi.framework.Bundle installBundle(String JavaDoc location, InputStream JavaDoc in) throws BundleException {
227         checkValid();
228         //note AdminPermission is checked after bundle is loaded
229
return framework.installBundle(location, in);
230     }
231
232     /**
233      * Retrieve the bundle that has the given unique identifier.
234      *
235      * @param id The identifier of the bundle to retrieve.
236      * @return A Bundle object, or <code>null</code>
237      * if the identifier doesn't match any installed bundle.
238      */

239     public org.osgi.framework.Bundle getBundle(long id) {
240         return (framework.getBundle(id));
241     }
242
243     /**
244      * Retrieve the bundle that has the given location.
245      *
246      * @param location The location string of the bundle to retrieve.
247      * @return A Bundle object, or <code>null</code>
248      * if the location doesn't match any installed bundle.
249      */

250     public AbstractBundle getBundleByLocation(String JavaDoc location) {
251         return (framework.getBundleByLocation(location));
252     }
253
254     /**
255      * Retrieve a list of all installed bundles.
256      * The list is valid at the time
257      * of the call to getBundles, but the framework is a very dynamic
258      * environment and bundles can be installed or uninstalled at anytime.
259      *
260      * @return An array of {@link AbstractBundle} objects, one
261      * object per installed bundle.
262      */

263     public org.osgi.framework.Bundle[] getBundles() {
264         return framework.getAllBundles();
265     }
266
267     /**
268      * Add a service listener with a filter.
269      * {@link ServiceListener}s are notified when a service has a lifecycle
270      * state change.
271      * See {@link #getServiceReferences(String, String) getServiceReferences}
272      * for a description of the filter syntax.
273      * The listener is added to the context bundle's list of listeners.
274      * See {@link #getBundle() getBundle()}
275      * for a definition of context bundle.
276      *
277      * <p>The listener is called if the filter criteria is met.
278      * To filter based upon the class of the service, the filter
279      * should reference the "objectClass" property.
280      * If the filter paramater is <code>null</code>, all services
281      * are considered to match the filter.
282      * <p>If the Java runtime environment supports permissions, then additional
283      * filtering is done.
284      * {@link AbstractBundle#hasPermission(Object) Bundle.hasPermission} is called for the
285      * bundle which defines the listener to validate that the listener has the
286      * {@link ServicePermission} permission to <code>"get"</code> the service
287      * using at least one of the named classes the service was registered under.
288      *
289      * @param listener The service listener to add.
290      * @param filter The filter criteria.
291      * @exception InvalidSyntaxException If the filter parameter contains
292      * an invalid filter string which cannot be parsed.
293      * @see ServiceEvent
294      * @see ServiceListener
295      * @exception java.lang.IllegalStateException
296      * If the bundle context has stopped.
297      */

298     public void addServiceListener(ServiceListener listener, String JavaDoc filter) throws InvalidSyntaxException {
299         checkValid();
300
301         if (Debug.DEBUG && Debug.DEBUG_EVENTS) {
302             String JavaDoc listenerName = listener.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(listener)); //$NON-NLS-1$
303
Debug.println("addServiceListener[" + bundle + "](" + listenerName + ", \"" + filter + "\")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
304
}
305
306         ServiceListener filteredListener = new FilteredServiceListener(filter, listener, this);
307
308         synchronized (framework.serviceEvent) {
309             if (serviceEvent == null) {
310                 serviceEvent = new EventListeners();
311                 framework.serviceEvent.addListener(this, this);
312             }
313
314             serviceEvent.addListener(listener, filteredListener);
315         }
316     }
317
318     /**
319      * Add a service listener.
320      *
321      * <p>This method is the same as calling
322      * {@link #addServiceListener(ServiceListener, String)}
323      * with filter set to <code>null</code>.
324      *
325      * @see #addServiceListener(ServiceListener, String)
326      */

327     public void addServiceListener(ServiceListener listener) {
328         try {
329             addServiceListener(listener, null);
330         } catch (InvalidSyntaxException e) {
331             if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
332                 Debug.println("InvalidSyntaxException w/ null filter" + e.getMessage()); //$NON-NLS-1$
333
Debug.printStackTrace(e);
334             }
335         }
336     }
337
338     /**
339      * Remove a service listener.
340      * The listener is removed from the context bundle's list of listeners.
341      * See {@link #getBundle() getBundle()}
342      * for a definition of context bundle.
343      *
344      * <p>If this method is called with a listener which is not registered,
345      * then this method does nothing.
346      *
347      * @param listener The service listener to remove.
348      * @exception java.lang.IllegalStateException
349      * If the bundle context has stopped.
350      */

351     public void removeServiceListener(ServiceListener listener) {
352         checkValid();
353
354         if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
355             String JavaDoc listenerName = listener.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(listener)); //$NON-NLS-1$
356
Debug.println("removeServiceListener[" + bundle + "](" + listenerName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
357
}
358
359         synchronized (framework.serviceEvent) {
360             if (serviceEvent != null) {
361                 serviceEvent.removeListener(listener);
362             }
363         }
364     }
365
366     /**
367      * Add a bundle listener.
368      * {@link BundleListener}s are notified when a bundle has a lifecycle
369      * state change.
370      * The listener is added to the context bundle's list of listeners.
371      * See {@link #getBundle() getBundle()}
372      * for a definition of context bundle.
373      *
374      * @param listener The bundle listener to add.
375      * @exception java.lang.IllegalStateException
376      * If the bundle context has stopped.
377      * @see BundleEvent
378      * @see BundleListener
379      */

380     public void addBundleListener(BundleListener listener) {
381         checkValid();
382
383         if (Debug.DEBUG && Debug.DEBUG_EVENTS) {
384             String JavaDoc listenerName = listener.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(listener)); //$NON-NLS-1$
385
Debug.println("addBundleListener[" + bundle + "](" + listenerName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
386
}
387
388         if (listener instanceof SynchronousBundleListener) {
389             framework.checkAdminPermission(getBundle(), AdminPermission.LISTENER);
390             synchronized (framework.bundleEventSync) {
391                 if (bundleEventSync == null) {
392                     bundleEventSync = new EventListeners();
393                     framework.bundleEventSync.addListener(this, this);
394                 }
395
396                 bundleEventSync.addListener(listener, listener);
397             }
398         } else {
399             synchronized (framework.bundleEvent) {
400                 if (bundleEvent == null) {
401                     bundleEvent = new EventListeners();
402                     framework.bundleEvent.addListener(this, this);
403                 }
404
405                 bundleEvent.addListener(listener, listener);
406             }
407         }
408     }
409
410     /**
411      * Remove a bundle listener.
412      * The listener is removed from the context bundle's list of listeners.
413      * See {@link #getBundle() getBundle()}
414      * for a definition of context bundle.
415      *
416      * <p>If this method is called with a listener which is not registered,
417      * then this method does nothing.
418      *
419      * @param listener The bundle listener to remove.
420      * @exception java.lang.IllegalStateException
421      * If the bundle context has stopped.
422      */

423     public void removeBundleListener(BundleListener listener) {
424         checkValid();
425
426         if (Debug.DEBUG && Debug.DEBUG_EVENTS) {
427             String JavaDoc listenerName = listener.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(listener)); //$NON-NLS-1$
428
Debug.println("removeBundleListener[" + bundle + "](" + listenerName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
429
}
430
431         if (listener instanceof SynchronousBundleListener) {
432             framework.checkAdminPermission(getBundle(), AdminPermission.LISTENER);
433
434             synchronized (framework.bundleEventSync) {
435                 if (bundleEventSync != null) {
436                     bundleEventSync.removeListener(listener);
437                 }
438             }
439         } else {
440             synchronized (framework.bundleEvent) {
441                 if (bundleEvent != null) {
442                     bundleEvent.removeListener(listener);
443                 }
444             }
445         }
446     }
447
448     /**
449      * Add a general framework listener.
450      * {@link FrameworkListener}s are notified of general framework events.
451      * The listener is added to the context bundle's list of listeners.
452      * See {@link #getBundle() getBundle()}
453      * for a definition of context bundle.
454      *
455      * @param listener The framework listener to add.
456      * @exception java.lang.IllegalStateException
457      * If the bundle context has stopped.
458      * @see FrameworkEvent
459      * @see FrameworkListener
460      */

461     public void addFrameworkListener(FrameworkListener listener) {
462         checkValid();
463
464         if (Debug.DEBUG && Debug.DEBUG_EVENTS) {
465             String JavaDoc listenerName = listener.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(listener)); //$NON-NLS-1$
466
Debug.println("addFrameworkListener[" + bundle + "](" + listenerName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
467
}
468
469         synchronized (framework.frameworkEvent) {
470             if (frameworkEvent == null) {
471                 frameworkEvent = new EventListeners();
472                 framework.frameworkEvent.addListener(this, this);
473             }
474
475             frameworkEvent.addListener(listener, listener);
476         }
477     }
478
479     /**
480      * Remove a framework listener.
481      * The listener is removed from the context bundle's list of listeners.
482      * See {@link #getBundle() getBundle()}
483      * for a definition of context bundle.
484      *
485      * <p>If this method is called with a listener which is not registered,
486      * then this method does nothing.
487      *
488      * @param listener The framework listener to remove.
489      * @exception java.lang.IllegalStateException
490      * If the bundle context has stopped.
491      */

492     public void removeFrameworkListener(FrameworkListener listener) {
493         checkValid();
494
495         if (Debug.DEBUG && Debug.DEBUG_EVENTS) {
496             String JavaDoc listenerName = listener.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(listener)); //$NON-NLS-1$
497
Debug.println("removeFrameworkListener[" + bundle + "](" + listenerName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
498
}
499
500         synchronized (framework.frameworkEvent) {
501             if (frameworkEvent != null) {
502                 frameworkEvent.removeListener(listener);
503             }
504         }
505     }
506
507     /**
508      * Register a service with multiple names.
509      * This method registers the given service object with the given properties
510      * under the given class names.
511      * A {@link ServiceRegistrationImpl} object is returned.
512      * The {@link ServiceRegistrationImpl} object is for the private use of the bundle
513      * registering the service and should not be shared with other bundles.
514      * The registering bundle is defined to be the context bundle.
515      * See {@link #getBundle()} for a definition of context bundle.
516      * Other bundles can locate the service by using either the
517      * {@link #getServiceReferences getServiceReferences} or
518      * {@link #getServiceReference getServiceReference} method.
519      *
520      * <p>A bundle can register a service object that implements the
521      * {@link ServiceFactory} interface to
522      * have more flexiblity in providing service objects to different
523      * bundles.
524      *
525      * <p>The following steps are followed to register a service:
526      * <ol>
527      * <li>If the service parameter is not a {@link ServiceFactory},
528      * an <code>IllegalArgumentException</code> is thrown if the
529      * service parameter is not an <code>instanceof</code>
530      * all the classes named.
531      * <li>The service is added to the framework's service registry
532      * and may now be used by other bundles.
533      * <li>A {@link ServiceEvent} of type {@link ServiceEvent#REGISTERED}
534      * is synchronously sent.
535      * <li>A {@link ServiceRegistrationImpl} object for this registration
536      * is returned.
537      * </ol>
538      *
539      * @param clazzes The class names under which the service can be located.
540      * The class names in this array will be stored in the service's
541      * properties under the key "objectClass".
542      * @param service The service object or a {@link ServiceFactory} object.
543      * @param properties The properties for this service.
544      * The keys in the properties object must all be Strings.
545      * Changes should not be made to this object after calling this method.
546      * To update the service's properties call the
547      * {@link ServiceRegistrationImpl#setProperties ServiceRegistration.setProperties}
548      * method.
549      * This parameter may be <code>null</code> if the service has no properties.
550      * @return A {@link ServiceRegistrationImpl} object for use by the bundle
551      * registering the service to update the
552      * service's properties or to unregister the service.
553      * @exception java.lang.IllegalArgumentException If one of the following is true:
554      * <ul>
555      * <li>The service parameter is null.
556      * <li>The service parameter is not a {@link ServiceFactory} and is not an
557      * <code>instanceof</code> all the named classes in the clazzes parameter.
558      * </ul>
559      * @exception java.lang.SecurityException If the caller does not have
560      * {@link ServicePermission} permission to "register" the service for
561      * all the named classes
562      * and the Java runtime environment supports permissions.
563      * @exception java.lang.IllegalStateException
564      * If the bundle context has stopped.
565      * @see ServiceRegistrationImpl
566      * @see ServiceFactory
567      */

568     public org.osgi.framework.ServiceRegistration registerService(String JavaDoc[] clazzes, Object JavaDoc service, Dictionary properties) {
569         checkValid();
570
571         if (service == null) {
572             if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
573                 Debug.println("Service object is null"); //$NON-NLS-1$
574
}
575
576             throw new IllegalArgumentException JavaDoc(Msg.SERVICE_ARGUMENT_NULL_EXCEPTION);
577         }
578
579         int size = clazzes.length;
580
581         if (size == 0) {
582             if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
583                 Debug.println("Classes array is empty"); //$NON-NLS-1$
584
}
585
586             throw new IllegalArgumentException JavaDoc(Msg.SERVICE_EMPTY_CLASS_LIST_EXCEPTION);
587         }
588
589         /* copy the array so that changes to the original will not affect us. */
590         String JavaDoc[] copy = new String JavaDoc[clazzes.length];
591         // doing this the hard way so we can intern the strings
592
for (int i = clazzes.length - 1; i >= 0; i--)
593             copy[i] = clazzes[i].intern();
594         clazzes = copy;
595
596         /* check for ServicePermissions. */
597         framework.checkRegisterServicePermission(clazzes);
598
599         if (!(service instanceof ServiceFactory)) {
600             String JavaDoc invalidService = checkServiceClass(clazzes, service);
601             if (invalidService != null) {
602                 if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
603                     Debug.println("Service object is not an instanceof " + invalidService); //$NON-NLS-1$
604
}
605                 throw new IllegalArgumentException JavaDoc(NLS.bind(Msg.SERVICE_NOT_INSTANCEOF_CLASS_EXCEPTION, invalidService));
606             }
607         }
608
609         return (createServiceRegistration(clazzes, service, properties));
610     }
611
612     //Return the name of the class that is not satisfied by the service object
613
static String JavaDoc checkServiceClass(final String JavaDoc[] clazzes, final Object JavaDoc serviceObject) {
614         ClassLoader JavaDoc cl = (ClassLoader JavaDoc) AccessController.doPrivileged(new PrivilegedAction() {
615             public Object JavaDoc run() {
616                 return serviceObject.getClass().getClassLoader();
617             }
618         });
619         for (int i = 0; i < clazzes.length; i++) {
620             try {
621                 Class JavaDoc serviceClazz = cl == null ? Class.forName(clazzes[i]) : cl.loadClass(clazzes[i]);
622                 if (!serviceClazz.isInstance(serviceObject))
623                     return clazzes[i];
624             } catch (ClassNotFoundException JavaDoc e) {
625                 //This check is rarely done
626
if (extensiveCheckServiceClass(clazzes[i], serviceObject.getClass()))
627                     return clazzes[i];
628             }
629         }
630         return null;
631     }
632
633     private static boolean extensiveCheckServiceClass(String JavaDoc clazz, Class JavaDoc serviceClazz) {
634         if (clazz.equals(serviceClazz.getName()))
635             return false;
636         Class JavaDoc[] interfaces = serviceClazz.getInterfaces();
637         for (int i = 0; i < interfaces.length; i++)
638             if (!extensiveCheckServiceClass(clazz, interfaces[i]))
639                 return false;
640         Class JavaDoc superClazz = serviceClazz.getSuperclass();
641         if (superClazz != null)
642             if (!extensiveCheckServiceClass(clazz, superClazz))
643                 return false;
644         return true;
645     }
646
647     /**
648      * Create a new ServiceRegistration object. This method is used so that it may be overridden
649      * by a secure implementation.
650      *
651      * @param clazzes The class names under which the service can be located.
652      * @param service The service object or a {@link ServiceFactory} object.
653      * @param properties The properties for this service.
654      * @return A {@link ServiceRegistrationImpl} object for use by the bundle.
655      */

656     protected ServiceRegistrationImpl createServiceRegistration(String JavaDoc[] clazzes, Object JavaDoc service, Dictionary properties) {
657         return (new ServiceRegistrationImpl(this, clazzes, service, properties));
658     }
659
660     /**
661      * Register a service with a single name.
662      * This method registers the given service object with the given properties
663      * under the given class name.
664      *
665      * <p>This method is otherwise identical to
666      * {@link #registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)}
667      * and is provided as a convenience when the service parameter will only be registered
668      * under a single class name.
669      *
670      * @see #registerService(java.lang.String[], java.lang.Object, java.util.Dictionary)
671      */

672     public org.osgi.framework.ServiceRegistration registerService(String JavaDoc clazz, Object JavaDoc service, Dictionary properties) {
673         String JavaDoc[] clazzes = new String JavaDoc[] {clazz};
674
675         return (registerService(clazzes, service, properties));
676     }
677
678     /**
679      * Returns a list of <tt>ServiceReference</tt> objects. This method returns a list of
680      * <tt>ServiceReference</tt> objects for services which implement and were registered under
681      * the specified class and match the specified filter criteria.
682      *
683      * <p>The list is valid at the time of the call to this method, however as the Framework is
684      * a very dynamic environment, services can be modified or unregistered at anytime.
685      *
686      * <p><tt>filter</tt> is used to select the registered service whose
687      * properties objects contain keys and values which satisfy the filter.
688      * See {@link FilterImpl}for a description of the filter string syntax.
689      *
690      * <p>If <tt>filter</tt> is <tt>null</tt>, all registered services
691      * are considered to match the filter.
692      * <p>If <tt>filter</tt> cannot be parsed, an {@link InvalidSyntaxException}will
693      * be thrown with a human readable message where the filter became unparsable.
694      *
695      * <p>The following steps are required to select a service:
696      * <ol>
697      * <li>If the Java Runtime Environment supports permissions, the caller is checked for the
698      * <tt>ServicePermission</tt> to get the service with the specified class.
699      * If the caller does not have the correct permission, <tt>null</tt> is returned.
700      * <li>If the filter string is not <tt>null</tt>, the filter string is
701      * parsed and the set of registered services which satisfy the filter is
702      * produced.
703      * If the filter string is <tt>null</tt>, then all registered services
704      * are considered to satisfy the filter.
705      * <li>If <code>clazz</code> is not <tt>null</tt>, the set is further reduced to
706      * those services which are an <tt>instanceof</tt> and were registered under the specified class.
707      * The complete list of classes of which a service is an instance and which
708      * were specified when the service was registered is available from the
709      * service's {@link Constants#OBJECTCLASS}property.
710      * <li>An array of <tt>ServiceReference</tt> to the selected services is returned.
711      * </ol>
712      *
713      * @param clazz The class name with which the service was registered, or
714      * <tt>null</tt> for all services.
715      * @param filter The filter criteria.
716      * @return An array of <tt>ServiceReference</tt> objects, or
717      * <tt>null</tt> if no services are registered which satisfy the search.
718      * @exception InvalidSyntaxException If <tt>filter</tt> contains
719      * an invalid filter string which cannot be parsed.
720      */

721     public org.osgi.framework.ServiceReference[] getServiceReferences(String JavaDoc clazz, String JavaDoc filter) throws InvalidSyntaxException {
722         checkValid();
723         if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
724             Debug.println("getServiceReferences(" + clazz + ", \"" + filter + "\")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
725
}
726         return (framework.getServiceReferences(clazz, filter, this, false));
727     }
728
729     public ServiceReference[] getAllServiceReferences(String JavaDoc clazz, String JavaDoc filter) throws InvalidSyntaxException {
730         checkValid();
731         if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
732             Debug.println("getAllServiceReferences(" + clazz + ", \"" + filter + "\")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
733
}
734         return (framework.getServiceReferences(clazz, filter, this, true));
735     }
736
737     /**
738      * Get a service reference.
739      * Retrieves a {@link ServiceReferenceImpl} for a service
740      * which implements the named class.
741      *
742      * <p>This reference is valid at the time
743      * of the call to this method, but since the framework is a very dynamic
744      * environment, services can be modified or unregistered at anytime.
745      *
746      * <p>This method is provided as a convenience for when the caller is
747      * interested in any service which implements a named class. This method is
748      * the same as calling {@link #getServiceReferences getServiceReferences}
749      * with a <code>null</code> filter string but only a single {@link ServiceReferenceImpl}
750      * is returned.
751      *
752      * @param clazz The class name which the service must implement.
753      * @return A {@link ServiceReferenceImpl} object, or <code>null</code>
754      * if no services are registered which implement the named class.
755      * @see #getServiceReferences
756      */

757     public org.osgi.framework.ServiceReference getServiceReference(String JavaDoc clazz) {
758         checkValid();
759
760         if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
761             Debug.println("getServiceReference(" + clazz + ")"); //$NON-NLS-1$ //$NON-NLS-2$
762
}
763
764         try {
765             ServiceReference[] references = framework.getServiceReferences(clazz, null, this, false);
766
767             if (references != null) {
768                 int index = 0;
769
770                 int length = references.length;
771
772                 if (length > 1) /* if more than one service, select highest ranking */{
773                     int rankings[] = new int[length];
774                     int count = 0;
775                     int maxRanking = Integer.MIN_VALUE;
776
777                     for (int i = 0; i < length; i++) {
778                         int ranking = ((ServiceReferenceImpl) references[i]).getRanking();
779
780                         rankings[i] = ranking;
781
782                         if (ranking > maxRanking) {
783                             index = i;
784                             maxRanking = ranking;
785                             count = 1;
786                         } else {
787                             if (ranking == maxRanking) {
788                                 count++;
789                             }
790                         }
791                     }
792
793                     if (count > 1) /* if still more than one service, select lowest id */{
794                         long minId = Long.MAX_VALUE;
795
796                         for (int i = 0; i < length; i++) {
797                             if (rankings[i] == maxRanking) {
798                                 long id = ((ServiceReferenceImpl) references[i]).getId();
799
800                                 if (id < minId) {
801                                     index = i;
802                                     minId = id;
803                                 }
804                             }
805                         }
806                     }
807                 }
808
809                 return (references[index]);
810             }
811         } catch (InvalidSyntaxException e) {
812             if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
813                 Debug.println("InvalidSyntaxException w/ null filter" + e.getMessage()); //$NON-NLS-1$
814
Debug.printStackTrace(e);
815             }
816         }
817
818         return (null);
819     }
820
821     /**
822      * Get a service's service object.
823      * Retrieves the service object for a service.
824      * A bundle's use of a service is tracked by a
825      * use count. Each time a service's service object is returned by
826      * {@link #getService}, the context bundle's use count for the service
827      * is incremented by one. Each time the service is release by
828      * {@link #ungetService}, the context bundle's use count
829      * for the service is decremented by one.
830      * When a bundle's use count for a service
831      * drops to zero, the bundle should no longer use the service.
832      * See {@link #getBundle()} for a definition of context bundle.
833      *
834      * <p>This method will always return <code>null</code> when the
835      * service associated with this reference has been unregistered.
836      *
837      * <p>The following steps are followed to get the service object:
838      * <ol>
839      * <li>If the service has been unregistered,
840      * <code>null</code> is returned.
841      * <li>The context bundle's use count for this service is incremented by one.
842      * <li>If the context bundle's use count for the service is now one and
843      * the service was registered with a {@link ServiceFactory},
844      * the {@link ServiceFactory#getService ServiceFactory.getService} method
845      * is called to create a service object for the context bundle.
846      * This service object is cached by the framework.
847      * While the context bundle's use count for the service is greater than zero,
848      * subsequent calls to get the services's service object for the context bundle
849      * will return the cached service object.
850      * <br>If the service object returned by the {@link ServiceFactory}
851      * is not an <code>instanceof</code>
852      * all the classes named when the service was registered or
853      * the {@link Serv