001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *   http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.felix.framework;
020    
021    import org.osgi.framework.launch.Framework;
022    import java.io.*;
023    import java.net.*;
024    import java.security.*;
025    import java.util.*;
026    
027    import org.apache.felix.framework.cache.*;
028    import org.apache.felix.framework.ext.SecurityProvider;
029    import org.apache.felix.framework.searchpolicy.*;
030    import org.apache.felix.framework.ServiceRegistry.ServiceRegistryCallbacks;
031    import org.apache.felix.framework.util.*;
032    import org.apache.felix.framework.util.manifestparser.*;
033    import org.apache.felix.moduleloader.*;
034    import org.osgi.framework.*;
035    import org.osgi.framework.hooks.service.*;
036    import org.osgi.service.packageadmin.ExportedPackage;
037    import org.osgi.service.startlevel.StartLevel;
038    
039    public class Felix extends BundleImpl implements Framework
040    {
041        // The secure action used to do privileged calls
042        static final SecureAction m_secureAction = new SecureAction();
043    
044        // The extension manager to handle extension bundles
045        ExtensionManager m_extensionManager;
046    
047        // Logging related member variables.
048        private final Logger m_logger;
049        // Immutable config properties.
050        private final Map m_configMap;
051        // Mutable configuration properties passed into constructor.
052        private final Map m_configMutableMap;
053    
054        // MODULE FACTORY.
055        private final FelixResolverState m_resolverState;
056        private final FelixResolver m_felixResolver;
057    
058        // Lock object used to determine if an individual bundle
059        // lock or the global lock can be acquired.
060        private final Object[] m_bundleLock = new Object[0];
061        // Keeps track of threads wanting to acquire the global lock.
062        private final List m_globalLockWaitersList = new ArrayList();
063        // The thread currently holding the global lock.
064        private Thread m_globalLockThread = null;
065        // How many times the global lock was acquired by the thread holding
066        // the global lock; if this value is zero, then it means the global
067        // lock is free.
068        private int m_globalLockCount = 0;
069    
070        // Maps a bundle location to a bundle location;
071        // used to reserve a location when installing a bundle.
072        private final Map m_installRequestMap = new HashMap();
073        // This lock must be acquired to modify m_installRequestMap;
074        // to help avoid deadlock this lock as priority 1 and should
075        // be acquired before locks with lower priority.
076        private final Object[] m_installRequestLock_Priority1 = new Object[0];
077    
078        // Maps a bundle location to a bundle.
079        private HashMap m_installedBundleMap;
080        private SortedMap m_installedBundleIndex;
081        // This lock must be acquired to modify m_installedBundleMap;
082        // to help avoid deadlock this lock as priority 2 and should
083        // be acquired before locks with lower priority.
084        private final Object[] m_installedBundleLock_Priority2 = new Object[0];
085    
086        // An array of uninstalled bundles before a refresh occurs.
087        private BundleImpl[] m_uninstalledBundles = null;
088        // This lock must be acquired to modify m_uninstalledBundles;
089        // to help avoid deadlock this lock as priority 3 and should
090        // be acquired before locks with lower priority.
091        private final Object[] m_uninstalledBundlesLock_Priority3 = new Object[0];
092    
093        // Framework's active start level.
094        private volatile int m_activeStartLevel = FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
095    
096        // Local bundle cache.
097        private BundleCache m_cache = null;
098    
099        // System bundle activator list.
100        List m_activatorList = null;
101    
102        // Next available bundle identifier.
103        private long m_nextId = 1L;
104        private final Object m_nextIdLock = new Object[0];
105    
106        // List of event listeners.
107        private EventDispatcher m_dispatcher = null;
108    
109        // Service registry.
110        private ServiceRegistry m_registry = null;
111    
112        // Reusable bundle URL stream handler.
113        private final URLStreamHandler m_bundleStreamHandler;
114    
115        // Boot package delegation.
116        private final String[] m_bootPkgs;
117        private final boolean[] m_bootPkgWildcards;
118    
119        // Shutdown thread.
120        private Thread m_shutdownThread = null;
121        private volatile ThreadGate m_shutdownGate = null;
122        
123        // Security Manager created by the framework
124        private SecurityManager m_securityManager = null;
125    
126        /**
127         * <p>
128         * This constructor creates a framework instance with a specified <tt>Map</tt>
129         * of configuration properties. Configuration properties are used internally
130         * by the framework to alter its default behavior. The configuration properties
131         * should have a <tt>String</tt> key and an <tt>Object</tt> value. The passed
132         * in <tt>Map</tt> is copied by the framework and all keys are converted to
133         * <tt>String</tt>s.
134         * </p>
135         * <p>
136         * Configuration properties are generally the sole means to configure the
137         * framework's default behavior; the framework does not typically refer to
138         * any system properties for configuration information. If a <tt>Map</tt> is
139         * supplied to this method for configuration properties, then the framework
140         * will consult the <tt>Map</tt> instance for any and all configuration
141         * properties. It is possible to specify a <tt>null</tt> for the configuration
142         * property map, in which case the framework will use its default behavior
143         * in all cases.
144         * </p>
145         * <p>
146         * The following configuration properties can be specified (properties starting
147         * with "<tt>felix</tt>" are specific to Felix, while those starting with
148         * "<tt>org.osgi</tt>" are standard OSGi properties):
149         * </p>
150         * <ul>
151         *   <li><tt>org.osgi.framework.storage</tt> - Sets the directory to use as
152         *       the bundle cache; by default bundle cache directory is
153         *       <tt>felix-cache</tt> in the current working directory. The value
154         *       should be a valid directory name. The directory name can be either absolute
155         *       or relative. Relative directory names are relative to the current working
156         *       directory. The specified directory will be created if it does
157         *       not exist.
158         *   </li>
159         *   <li><tt>org.osgi.framework.storage.clean</tt> - Determines whether the
160         *       bundle cache is flushed. The value can either be "<tt>none</tt>"
161         *       or "<tt>onFirstInit</tt>", where "<tt>none</tt>" does not flush
162         *       the bundle cache and "<tt>onFirstInit</tt>" flushes the bundle
163         *       cache when the framework instance is first initialized. The default
164         *       value is "<tt>none</tt>".
165         *   </li>
166         *   <li><tt>felix.cache.rootdir</tt> - Sets the root directory to use to
167         *       calculate the bundle cache directory for relative directory names. If
168         *       <tt>org.osgi.framework.storage</tt> is set to a relative name, by
169         *       default it is relative to the current working directory. If this
170         *       property is set, then it will be calculated as being relative to
171         *       the specified root directory.
172         *   </li>
173         *   <li><tt>felix.cache.bufsize</tt> - Sets the buffer size to be used by
174         *       the cache; the default value is 4096. The integer value of this
175         *       string provides control over the size of the internal buffer of the
176         *       disk cache for performance reasons.
177         *   </li>
178         *   <li><tt>org.osgi.framework.system.packages</tt> - Specifies a
179         *       comma-delimited list of packages that should be exported via the
180         *       System Bundle from the parent class loader. The framework will set
181         *       this to a reasonable default. If the value is specified, it
182         *       replaces any default value.
183         *   </li>
184         *   <li><tt>org.osgi.framework.system.packages.extra</tt> - Specifies a
185         *       comma-delimited list of packages that should be exported via the
186         *       System Bundle from the parent class loader in addition to the
187         *       packages in <tt>org.osgi.framework.system.packages</tt>. The default
188         *       value is empty. If a value is specified, it is appended to the list
189         *       of default or specified packages in
190         *       <tt>org.osgi.framework.system.packages</tt>.
191         *   </li>
192         *   <li><tt>org.osgi.framework.bootdelegation</tt> - Specifies a
193         *       comma-delimited list of packages that should be made implicitly
194         *       available to all bundles from the parent class loader. It is
195         *       recommended not to use this property since it breaks modularity.
196         *       The default value is empty.
197         *   </li>
198         *   <li><tt>felix.systembundle.activators</tt> - A <tt>List</tt> of
199         *       <tt>BundleActivator</tt> instances that are started/stopped when
200         *       the System Bundle is started/stopped. The specified instances will
201         *       receive the System Bundle's <tt>BundleContext</tt> when invoked.
202         *   </li>
203         *   <li><tt>felix.log.logger</tt> - An instance of <tt>Logger</tt> that the
204         *       framework uses as its default logger.
205         *   </li>
206         *   <li><tt>felix.log.level</tt> - An integer value indicating the degree
207         *       of logging reported by the framework; the higher the value the more
208         *       logging is reported. If zero ('0') is specified, then logging is
209         *       turned off completely. The log levels match those specified in the
210         *       OSGi Log Service (i.e., 1 = error, 2 = warning, 3 = information,
211         *       and 4 = debug). The default value is 1.
212         *   </li>
213         *   <li><tt>org.osgi.framework.startlevel.beginning</tt> - The initial
214         *       start level of the framework once it starts execution; the default
215         *       value is 1.
216         *   </li>
217         *   <li><tt>felix.startlevel.bundle</tt> - The default start level for
218         *       newly installed bundles; the default value is 1.
219         *   </li>
220         *   <li><tt>felix.service.urlhandlers</tt> - Flag to indicate whether
221         *       to activate the URL Handlers service for the framework instance;
222         *       the default value is "<tt>true</tt>". Activating the URL Handlers
223         *       service will result in the <tt>URL.setURLStreamHandlerFactory()</tt>
224         *       and <tt>URLConnection.setContentHandlerFactory()</tt> being called.
225         *   </li>
226         *   <li><tt>felix.fragment.validation</tt> - Determines if installing
227         *       unsupported fragment bundles throws an exception or logs a warning.
228         *       Possible values are "<tt>exception</tt>" or "<tt>warning</tt>". The
229         *       default value is "<tt>exception</tt>".
230         * </ul>
231         * <p>
232         * The <a href="Main.html"><tt>Main</tt></a> class implements some
233         * functionality for default property file handling, which makes it
234         * possible to specify configuration properties and framework properties
235         * in files that are automatically loaded when starting the framework. If you
236         * plan to create your own framework instance, you may be
237         * able to take advantage of the features it provides; refer to its
238         * class documentation for more information.
239         * </p>
240         * <p>
241         * The framework is not actually started until the <tt>start()</tt> method
242         * is called.
243         * </p>
244         *
245         * @param configMap A map for obtaining configuration properties,
246         *        may be <tt>null</tt>.
247        **/
248        public Felix(Map configMap)
249        {
250            super();
251            // Copy the configuration properties; convert keys to strings.
252            m_configMutableMap = new StringMap(false);
253            if (configMap != null)
254            {
255                for (Iterator i = configMap.entrySet().iterator(); i.hasNext(); )
256                {
257                    Map.Entry entry = (Map.Entry) i.next();
258                    m_configMutableMap.put(entry.getKey().toString(), entry.getValue());
259                }
260            }
261            m_configMap = createUnmodifiableMap(m_configMutableMap);
262    
263            // Create logger with appropriate log level. Even though the
264            // logger needs the system bundle's context for tracking log
265            // services, it is created now because it is needed before
266            // the system bundle is activated. The system bundle's context
267            // will be set in the init() method after the system bundle
268            // is activated.
269            if (m_configMutableMap.get(FelixConstants.LOG_LOGGER_PROP) != null)
270            {
271                m_logger = (Logger) m_configMutableMap.get(FelixConstants.LOG_LOGGER_PROP);
272            }
273            else
274            {
275                m_logger = new Logger();
276            }
277            try
278            {
279                m_logger.setLogLevel(
280                    Integer.parseInt(
281                        (String) m_configMutableMap.get(FelixConstants.LOG_LEVEL_PROP)));
282            }
283            catch (NumberFormatException ex)
284            {
285                // Ignore and just use the default logging level.
286            }
287    
288            // Initialize framework properties.
289            initializeFrameworkProperties();
290    
291            // Create default bundle stream handler.
292            m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
293    
294            // Create a resolver and its state.
295            m_resolverState = new FelixResolverState(m_logger);
296            m_felixResolver = new FelixResolver(
297                new Resolver(m_logger,
298                    (String) m_configMap.get(Constants.FRAMEWORK_EXECUTIONENVIRONMENT)),
299                m_resolverState);
300    
301            // Create the extension manager, which we will use as the module
302            // definition for creating the system bundle module.
303            m_extensionManager = new ExtensionManager(m_logger, this);
304            try
305            {
306                addModule(m_extensionManager.getModule());
307            }
308            catch (Exception ex)
309            {
310                // This should not throw an exception, but if so, lets convert it to
311                // a runtime exception.
312                throw new RuntimeException(ex.getMessage());
313            }
314    
315            // Read the boot delegation property and parse it.
316            String s = (m_configMap == null)
317                ? null
318                : (String) m_configMap.get(Constants.FRAMEWORK_BOOTDELEGATION);
319            s = (s == null) ? "java.*" : s + ",java.*";
320            StringTokenizer st = new StringTokenizer(s, " ,");
321            m_bootPkgs = new String[st.countTokens()];
322            m_bootPkgWildcards = new boolean[m_bootPkgs.length];
323            for (int i = 0; i < m_bootPkgs.length; i++)
324            {
325                s = st.nextToken();
326                if (s.equals("*") || s.endsWith(".*"))
327                {
328                    m_bootPkgWildcards[i] = true;
329                    s = s.substring(0, s.length() - 1);
330                }
331                m_bootPkgs[i] = s;
332            }
333        }
334    
335        Logger getLogger()
336        {
337            return m_logger;
338        }
339    
340        Map getConfig()
341        {
342            return m_configMap;
343        }
344    
345        FelixResolver getResolver()
346        {
347            return m_felixResolver;
348        }
349    
350        FelixResolverState getResolverState()
351        {
352            return m_resolverState;
353        }
354    
355        URLStreamHandler getBundleStreamHandler()
356        {
357            return m_bundleStreamHandler;
358        }
359    
360        String[] getBootPackages()
361        {
362            return m_bootPkgs;
363        }
364    
365        boolean[] getBootPackageWildcards()
366        {
367            return m_bootPkgWildcards;
368        }
369    
370        private Map createUnmodifiableMap(Map mutableMap)
371        {
372            Map result = Collections.unmodifiableMap(mutableMap);
373    
374            // Work around a bug in certain version of J9 where a call to
375            // Collections.unmodifiableMap().keySet().iterator() throws
376            // a NoClassDefFoundError. We try to detect this and return
377            // the given mutableMap instead.
378            try
379            {
380                result.keySet().iterator();
381            }
382            catch (NoClassDefFoundError ex)
383            {
384                return mutableMap;
385            }
386    
387            return result;
388        }
389    
390        // This overrides the default behavior of BundleImpl.getFramework()
391        // to return "this", since the system bundle is the framework.
392        Felix getFramework()
393        {
394            return this;
395        }
396    
397        public long getBundleId()
398        {
399            return 0;
400        }
401    
402        public long getLastModified()
403        {
404            return 0;
405        }
406    
407        void setLastModified(long l)
408        {
409            // Ignore.
410        }
411    
412        String _getLocation()
413        {
414            return Constants.SYSTEM_BUNDLE_LOCATION;
415        }
416    
417        public int getPersistentState()
418        {
419            return Bundle.ACTIVE;
420        }
421    
422        public void setPersistentStateInactive()
423        {
424            // Ignore.
425        }
426    
427        public void setPersistentStateActive()
428        {
429            // Ignore.
430        }
431    
432        public void setPersistentStateUninstalled()
433        {
434            // Ignore.
435        }
436    
437        /**
438         * Overrides standard <tt>BundleImpl.getStartLevel()</tt> behavior to
439         * always return zero for the system bundle.
440         * @param defaultLevel This parameter is ignored by the system bundle.
441         * @return Always returns zero.
442        **/
443        int getStartLevel(int defaultLevel)
444        {
445            return 0;
446        }
447    
448        /**
449         * Overrides standard <tt>BundleImpl.setStartLevel()</tt> behavior to
450         * always throw an exception since the system bundle's start level cannot
451         * be changed.
452         * @param level This parameter is ignored by the system bundle.
453         * @throws IllegalArgumentException Always throws exception since system
454         *         bundle's start level cannot be changed.
455        **/
456        void setStartLevel(int level)
457        {
458            throw new IllegalArgumentException("Cannot set the system bundle's start level.");
459        }
460    
461        public boolean hasPermission(Object obj)
462        {
463            return true;
464        }
465    
466        /**
467         * This method initializes the framework, which is comprised of resolving
468         * the system bundle, reloading any cached bundles, and activating the system
469         * bundle. The framework is left in the <tt>Bundle.STARTING</tt> state and
470         * reloaded bundles are in the <tt>Bundle.INSTALLED</tt> state. After
471         * successfully invoking this method, <tt>getBundleContext()</tt> will
472         * return a valid <tt>BundleContext</tt> for the system bundle. To finish
473         * starting the framework, invoke the <tt>start()</tt> method.
474         *
475         * @throws org.osgi.framework.BundleException if any error occurs.
476        **/
477        public void init() throws BundleException
478        {
479            // The system bundle can only be initialized if it currently isn't started.
480            acquireBundleLock(this,
481                Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE);
482            try
483            {
484                String security = (String) m_configMap.get(Constants.FRAMEWORK_SECURITY);
485                if (security != null)
486                {
487                    if (System.getSecurityManager() != null)
488                    {
489                        throw new SecurityException("SecurityManager already installed");
490                    }
491                    security = security.trim();
492                    if (Constants.FRAMEWORK_SECURITY_OSGI.equalsIgnoreCase(security) || (security.length() == 0))
493                    {
494                        // TODO: security - we only need our own security manager to convert the exceptions
495                        //       because the 4.2.0 ct does expect them like this in one case. 
496                        System.setSecurityManager(m_securityManager = new SecurityManager()
497                        {
498                            public void checkPermission(Permission perm) 
499                            {
500                                try
501                                {
502                                    super.checkPermission(perm);
503                                }
504                                catch (AccessControlException ex)
505                                {
506                                    throw new SecurityException(ex);
507                                }
508                            }
509                        });
510                    }
511                    else
512                    {
513                        try 
514                        {
515                            System.setSecurityManager(m_securityManager = 
516                                (SecurityManager) Class.forName(security).newInstance());
517                        } 
518                        catch (Throwable t)
519                        {
520                            throw new SecurityException("Unable to install custom SecurityManager: " + security, t); 
521                        }
522                    }
523                }
524                if ((getState() == Bundle.INSTALLED) || (getState() == Bundle.RESOLVED))
525                {
526                    // Get any system bundle activators.
527                    m_activatorList = (List) m_configMutableMap.get(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP);
528                    m_activatorList = (m_activatorList == null) ? new ArrayList() : new ArrayList(m_activatorList);
529    
530                    // Initialize event dispatcher.
531                    m_dispatcher = EventDispatcher.start(m_logger);
532    
533                    // Create the bundle cache, if necessary, so that we can reload any
534                    // installed bundles.
535                    m_cache = (BundleCache) m_configMutableMap.get(
536                        FelixConstants.FRAMEWORK_BUNDLECACHE_IMPL);
537                    if (m_cache == null)
538                    {
539                           try
540                           {
541                               m_cache = new BundleCache(m_logger, m_configMap);
542                           }
543                           catch (Exception ex)
544                           {
545                               m_logger.log(Logger.LOG_ERROR, "Error creating bundle cache.", ex);
546                               throw new BundleException("Error creating bundle cache.", ex);
547                           }
548                    }
549    
550                    // If this is the first time init is called, check to see if
551                    // we need to flush the bundle cache.
552                    if (getState() == Bundle.INSTALLED)
553                    {
554                        String clean = (String) m_configMap.get(Constants.FRAMEWORK_STORAGE_CLEAN);
555                        if ((clean != null)
556                            && clean.equalsIgnoreCase(Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT))
557                        {
558                            try
559                            {
560                                m_cache.delete();
561                            }
562                            catch (Exception ex)
563                            {
564                                throw new BundleException("Unable to flush bundle cache.", ex);
565                            }
566                        }
567                    }
568    
569                    // Initialize installed bundle data structures.
570                    m_installedBundleMap = new HashMap();
571                    m_installedBundleIndex = new TreeMap();
572    
573                    // Add the system bundle to the set of installed bundles.
574                    m_installedBundleMap.put(_getLocation(), this);
575                    m_installedBundleIndex.put(new Long(0), this);
576    
577                    // Manually resolve the system bundle, which will cause its
578                    // state to be set to RESOLVED.
579                    try
580                    {
581                        m_felixResolver.resolve(getCurrentModule());
582                    }
583                    catch (ResolveException ex)
584                    {
585                        // This should never happen.
586                        throw new BundleException(
587                            "Unresolved constraint in System Bundle:"
588                            + ex.getRequirement());
589                    }
590    
591                    // Reload the cached bundles before creating and starting the
592                    // system bundle, since we want all cached bundles to be reloaded
593                    // when we activate the system bundle and any subsequent system
594                    // bundle activators passed into the framework constructor.
595                    BundleArchive[] archives = null;
596    
597                    // First get cached bundle identifiers.
598                    try
599                    {
600                        archives = m_cache.getArchives();
601                    }
602                    catch (Exception ex)
603                    {
604                        m_logger.log(Logger.LOG_ERROR, "Unable to list saved bundles.", ex);
605                        archives = null;
606                    }
607    
608                    // Now load all cached bundles.
609                    for (int i = 0; (archives != null) && (i < archives.length); i++)
610                    {
611                        try
612                        {
613                            // Keep track of the max bundle ID currently in use since we
614                            // will need to use this as our next bundle ID value if the
615                            // persisted value cannot be read.
616                            m_nextId = Math.max(m_nextId, archives[i].getId() + 1);
617    
618                            // It is possible that a bundle in the cache was previously
619                            // uninstalled, but not completely deleted (perhaps because
620                            // of a crash or a locked file), so if we see an archive
621                            // with an UNINSTALLED persistent state, then try to remove
622                            // it now.
623                            if (archives[i].getPersistentState() == Bundle.UNINSTALLED)
624                            {
625                                archives[i].closeAndDelete();
626                            }
627                            // Otherwise re-install the cached bundle.
628                            else
629                            {
630                                // Install the cached bundle.
631                                installBundle(
632                                    archives[i].getId(), archives[i].getLocation(), archives[i], null);
633                            }
634                        }
635                        catch (Exception ex)
636                        {
637    ex.printStackTrace();
638                            fireFrameworkEvent(FrameworkEvent.ERROR, this, ex);
639                            try
640                            {
641                                m_logger.log(
642                                    Logger.LOG_ERROR,
643                                    "Unable to re-install " + archives[i].getLocation(),
644                                    ex);
645                            }
646                            catch (Exception ex2)
647                            {
648                                m_logger.log(
649                                    Logger.LOG_ERROR,
650                                    "Unable to re-install cached bundle.",
651                                    ex);
652                            }
653                            // TODO: FRAMEWORK - Perhaps we should remove the cached bundle?
654                        }
655                    }
656    
657                    // Now that we have loaded all cached bundles and have determined the
658                    // max bundle ID of cached bundles, we need to try to load the next
659                    // bundle ID from persistent storage. In case of failure, we should
660                    // keep the max value.
661                    m_nextId = Math.max(m_nextId, loadNextId());
662    
663                    // Create service registry.
664                    m_registry = new ServiceRegistry(m_logger, new ServiceRegistryCallbacks() {
665                        public void serviceChanged(ServiceEvent event, Dictionary oldProps)
666                        {
667                            fireServiceEvent(event, oldProps);
668                        }
669                    });
670                    m_dispatcher.setServiceRegistry(m_registry);
671    
672                    // The framework is now in its startup sequence.
673                    setBundleStateAndNotify(this, Bundle.STARTING);
674    
675                    // Now it is possible for threads to wait for the framework to stop,
676                    // so create a gate for that purpose.
677                    m_shutdownGate = new ThreadGate();
678    
679                    // Create system bundle activator and bundle context so we can activate it.
680                    setActivator(new SystemBundleActivator());
681                    setBundleContext(new BundleContextImpl(m_logger, this, this));
682                    try
683                    {
684                        Felix.m_secureAction.startActivator(
685                            getActivator(), _getBundleContext());
686                    }
687                    catch (Throwable ex)
688                    {
689                        EventDispatcher.shutdown();
690                        m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
691                        throw new RuntimeException("Unable to start system bundle.");
692                    }
693    
694                    // Now that the system bundle is successfully created we can give
695                    // its bundle context to the logger so that it can track log services.
696                    m_logger.setSystemBundleContext(_getBundleContext());
697                }
698            }
699            finally
700            {
701                releaseBundleLock(this);
702            }
703        }
704    
705        /**
706         * This method starts the framework instance, which will transition the
707         * framework from start level 0 to its active start level as specified in
708         * its configuration properties (1 by default). If the <tt>init()</tt> was
709         * not explicitly invoked before calling this method, then it will be
710         * implicitly invoked before starting the framework.
711         *
712         * @throws org.osgi.framework.BundleException if any error occurs.
713        **/
714        public void start() throws BundleException
715        {
716            int startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
717    
718            acquireBundleLock(this,
719                Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE);
720            try
721            {
722                // Initialize if necessary.
723                if ((getState() == Bundle.INSTALLED) || (getState() == Bundle.RESOLVED))
724                {
725                    init();
726                }
727    
728                // If the current state is STARTING, then the system bundle can be started.
729                if (getState() == Bundle.STARTING)
730                {
731                    // Get the framework's default start level.
732                    String s = (String) m_configMap.get(Constants.FRAMEWORK_BEGINNING_STARTLEVEL);
733                    if (s != null)
734                    {
735                        try
736                        {
737                            startLevel = Integer.parseInt(s);
738                        }
739                        catch (NumberFormatException ex)
740                        {
741                            startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
742                        }
743                    }
744    
745                    // Set the start level using the start level service;
746                    // this ensures that all start level requests are
747                    // serialized.
748                    StartLevel sl = null;
749                    try
750                    {
751                        sl = (StartLevel) getService(
752                            getBundle(0), getServiceReferences((BundleImpl) getBundle(0),
753                            StartLevel.class.getName(), null, true)[0]);
754                    }
755                    catch (InvalidSyntaxException ex)
756                    {
757                        // Should never happen.
758                    }
759    
760                    if (sl instanceof StartLevelImpl)
761                    {
762                        ((StartLevelImpl) sl).setStartLevelAndWait(startLevel);
763                    }
764                    else
765                    {
766                        sl.setStartLevel(startLevel);
767                    }
768    
769                    // The framework is now running.
770                    setBundleStateAndNotify(this, Bundle.ACTIVE);
771                }
772            }
773            finally
774            {
775                releaseBundleLock(this);
776            }
777    
778            // Fire started event for system bundle.
779            fireBundleEvent(BundleEvent.STARTED, this);
780    
781            // Send a framework event to indicate the framework has started.
782            fireFrameworkEvent(FrameworkEvent.STARTED, this, null);
783        }
784    
785        public void start(int options) throws BundleException
786        {
787            // TODO: FRAMEWORK - For now, ignore all options when starting the
788            //       system bundle.
789            start();
790        }
791    
792        /**
793         * This method asynchronously shuts down the framework, it must be called at the
794         * end of a session in order to shutdown all active bundles.
795        **/
796        public void stop() throws BundleException
797        {
798            Object sm = System.getSecurityManager();
799    
800            if (sm != null)
801            {
802                ((SecurityManager) sm).checkPermission(new AdminPermission(this,
803                    AdminPermission.EXECUTE));
804            }
805    
806            stopBundle(this, true);
807        }
808    
809        public void stop(int options) throws BundleException
810        {
811            // TODO: FRAMEWORK - For now, ignore all options when stopping the
812            //       system bundle.
813            stop();
814        }
815    
816        /**
817         * This method will cause the calling thread to block until the framework
818         * shuts down.
819         * @param timeout A timeout value.
820         * @throws java.lang.InterruptedException If the thread was interrupted.
821        **/
822        public FrameworkEvent waitForStop(long timeout) throws InterruptedException
823        {
824            // Throw exception if timeout is negative.
825            if (timeout < 0)
826            {
827                throw new IllegalArgumentException("Timeout cannot be negative.");
828            }
829    
830            // If there is a gate, wait on it; otherwise, return immediately.
831            // Grab a copy of the gate, since it is volatile.
832            ThreadGate gate = m_shutdownGate;
833            boolean open = false;
834            if (gate != null)
835            {
836                open = gate.await(timeout);
837            }
838    
839            FrameworkEvent event;
840            if (open && (gate.getMessage() != null))
841            {
842                event = (FrameworkEvent) gate.getMessage();
843            }
844            else if (!open && (gate != null))
845            {
846                event = new FrameworkEvent(FrameworkEvent.WAIT_TIMEDOUT, this, null);
847            }
848            else
849            {
850                event = new FrameworkEvent(FrameworkEvent.STOPPED, this, null);
851            }
852            return event;
853        }
854    
855        public void uninstall() throws BundleException
856        {
857            throw new BundleException("Cannot uninstall the system bundle.");
858        }
859    
860        public void update() throws BundleException
861        {
862            update(null);
863        }
864    
865        public void update(InputStream is) throws BundleException
866        {
867            Object sm = System.getSecurityManager();
868    
869            if (sm != null)
870            {
871                ((SecurityManager) sm).checkPermission(new AdminPermission(this,
872                    AdminPermission.EXECUTE));
873            }
874    
875            // Spec says to close input stream first.
876            try
877            {
878                if (is != null) is.close();
879            }
880            catch (IOException ex)
881            {
882                m_logger.log(Logger.LOG_WARNING, "Exception closing input stream.", ex);
883            }
884    
885            // Then to stop and restart the framework on a separate thread.
886            new Thread(new Runnable() {
887                public void run()
888                {
889                    try
890                    {
891                        // First acquire the system bundle lock to verify the state.
892                        acquireBundleLock(Felix.this, Bundle.STARTING | Bundle.ACTIVE);
893                        // Set the reason for the shutdown.
894                        m_shutdownGate.setMessage(
895                            new FrameworkEvent(FrameworkEvent.STOPPED_UPDATE, Felix.this, null));
896                        // Record the state and stop the system bundle.
897                        int oldState = Felix.this.getState();
898                        try
899                        {
900                            stop();
901                        }
902                        catch (BundleException ex)
903                        {
904                            m_logger.log(Logger.LOG_WARNING, "Exception stopping framework.", ex);
905                        }
906                        finally
907                        {
908                            releaseBundleLock(Felix.this);
909                        }
910    
911                        // Make sure the framework is stopped.
912                        try
913                        {
914                            waitForStop(0);
915                        }
916                        catch (InterruptedException ex)
917                        {
918                            m_logger.log(Logger.LOG_WARNING, "Did not wait for framework to stop.", ex);
919                        }
920    
921                        // Depending on the old state, restart the framework.
922                        try
923                        {
924                            switch (oldState)
925                            {
926                                case Bundle.STARTING:
927                                    init();
928                                    break;
929                                case Bundle.ACTIVE:
930                                    start();
931                                    break;
932                            }
933                        }
934                        catch (BundleException ex)
935                        {
936                            m_logger.log(Logger.LOG_WARNING, "Exception restarting framework.", ex);
937                        }
938                    }
939                    catch (Exception ex)
940                    {
941                        m_logger.log(Logger.LOG_WARNING, "Cannot update an inactive framework.");
942                    }
943                }
944            }).start();
945        }
946    
947        public String toString()
948        {
949            return getSymbolicName() + " [" + getBundleId() +"]";
950        }
951    
952        /**
953         * Returns the active start level of the framework; this method
954         * implements functionality for the Start Level service.
955         * @return The active start level of the framework.
956        **/
957        int getActiveStartLevel()
958        {
959            return m_activeStartLevel;
960        }
961    
962        /**
963         * Implements the functionality of the <tt>setStartLevel()</tt>
964         * method for the StartLevel service, but does not do the security or
965         * parameter check. The security and parameter check are done in the
966         * StartLevel service implementation because this method is called on
967         * a separate thread and the caller's thread would already be gone if
968         * we did the checks in this method. This method should not be called
969         * directly.
970         * @param requestedLevel The new start level of the framework.
971        **/
972        void setActiveStartLevel(int requestedLevel)
973        {
974            Bundle[] bundles = null;
975    
976            // Do nothing if the requested start level is the same as the
977            // active start level.
978            if (requestedLevel != getActiveStartLevel())
979            {
980                // Synchronization for changing the start level is rather loose.
981                // The framework's active start level is volatile, so no lock is
982                // needed to access it. The install lock is acquired to attain a
983                // sorted snapshot of the currently installed bundles, but then this
984                // lock is freed immediately. No locks are held while processing the
985                // currently installed bundles for starting/stopping based on the new
986                // active start level. The only locking that occurs is for individual
987                // bundles when startBundle()/stopBundle() is called, but this locking
988                // is done in the respective method.
989                //
990                // This approach does mean that it is possible for a for individual
991                // bundle states to change during this operation. For example, bundle
992                // start levels can be changed or bundles can be uninstalled. If a
993                // bundle's start level changes, then it is possible for it to be
994                // processed out of order. Uninstalled bundles are just logged and
995                // ignored. I had a bit of discussion with Peter Kriens about these
996                // issues and he felt they were consistent with the spec, which
997                // intended Start Level to have some leeway.
998                //
999                // Calls to this method are only made by the start level thread, which
1000                // serializes framework start level changes. Thus, it is not possible
1001                // for two requests to change the framework's start level to interfere
1002                // with each other.
1003    
1004                // Determine if we are lowering or raising the
1005                // active start level.
1006                boolean lowering = (requestedLevel < getActiveStartLevel());
1007    
1008                synchronized (m_installedBundleLock_Priority2)
1009                {
1010                    // Get a snapshot of all installed bundles.
1011                    bundles = getBundles();
1012    
1013                    // Sort bundle array by start level either ascending or
1014                    // descending depending on whether the start level is being
1015                    // lowered or raised to that the bundles can be efficiently
1016                    // processed in order. Within a start level sort by bundle ID.
1017                    Comparator comparator = null;
1018                    if (lowering)
1019                    {
1020                        // Sort descending to stop highest start level first.
1021                        comparator = new Comparator() {
1022                            public int compare(Object o1, Object o2)
1023                            {
1024                                BundleImpl b1 = (BundleImpl) o1;
1025                                BundleImpl b2 = (BundleImpl) o2;
1026                                if (b1.getStartLevel(getInitialBundleStartLevel())
1027                                    < b2.getStartLevel(getInitialBundleStartLevel()))
1028                                {
1029                                    return 1;
1030                                }
1031                                else if (b1.getStartLevel(getInitialBundleStartLevel())
1032                                    > b2.getStartLevel(getInitialBundleStartLevel()))
1033                                {
1034                                    return -1;
1035                                }
1036                                else if (b1.getBundleId() < b2.getBundleId())
1037                                {
1038                                    return 1;
1039                                }
1040                                return -1;
1041                            }
1042                        };
1043                    }
1044                    else
1045                    {
1046                        // Sort ascending to start lowest start level first.
1047                        comparator = new Comparator() {
1048                            public int compare(Object o1, Object o2)
1049                            {
1050                                BundleImpl b1 = (BundleImpl) o1;
1051                                BundleImpl b2 = (BundleImpl) o2;
1052                                if (b1.getStartLevel(getInitialBundleStartLevel())
1053                                    > b2.getStartLevel(getInitialBundleStartLevel()))
1054                                {
1055                                    return 1;
1056                                }
1057                                else if (b1.getStartLevel(getInitialBundleStartLevel())
1058                                    < b2.getStartLevel(getInitialBundleStartLevel()))
1059                                {
1060                                    return -1;
1061                                }
1062                                else if (b1.getBundleId() > b2.getBundleId())
1063                                {
1064                                    return 1;
1065                                }
1066                                return -1;
1067                            }
1068                        };
1069                    }
1070    
1071                    Arrays.sort(bundles, comparator);
1072                }
1073    
1074                // Stop or start the bundles according to the start level.
1075                for (int i = 0; (bundles != null) && (i < bundles.length); i++)
1076                {
1077                    BundleImpl impl = (BundleImpl) bundles[i];
1078    
1079                    // Ignore the system bundle, since its start() and
1080                    // stop() methods get called explicitly in Felix.start()
1081                    // and Felix.stop(), respectively.
1082                    if (impl.getBundleId() == 0)
1083                    {
1084                        continue;
1085                    }
1086    
1087                    // Lock the current bundle.
1088                    try
1089                    {
1090                        acquireBundleLock(impl,
1091                            Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE
1092                            | Bundle.STARTING | Bundle.STOPPING);
1093                    }
1094                    catch (IllegalStateException ex)
1095                    {
1096                        // Ignore if the bundle has been uninstalled.
1097                        if (impl.getState() != Bundle.UNINSTALLED)
1098                        {
1099                            fireFrameworkEvent(FrameworkEvent.ERROR, impl, ex);
1100                            m_logger.log(
1101                                Logger.LOG_ERROR,
1102                                "Error locking " + impl._getLocation(), ex);
1103                        }
1104                        continue;
1105                    }
1106    
1107                    try
1108                    {
1109                        // Start the bundle if necessary.
1110                        if (((impl.getPersistentState() == Bundle.ACTIVE)
1111                            || (impl.getPersistentState() == Bundle.STARTING))
1112                            && (impl.getStartLevel(getInitialBundleStartLevel())
1113                                <= requestedLevel))
1114                        {
1115    
1116                            if (m_activeStartLevel != impl.getStartLevel(getInitialBundleStartLevel()))
1117                            {
1118                                m_activeStartLevel = impl.getStartLevel(getInitialBundleStartLevel());
1119                            }
1120                            
1121                            try
1122                            {
1123    // TODO: LAZY - Not sure if this is the best way...
1124                                int options = Bundle.START_TRANSIENT;
1125                                options = (impl.getPersistentState() == Bundle.STARTING)
1126                                    ? options | Bundle.START_ACTIVATION_POLICY
1127                                    : options;
1128                                startBundle(impl, options);
1129                            }
1130                            catch (Throwable th)
1131                            {
1132                                fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
1133                                m_logger.log(
1134                                    Logger.LOG_ERROR,
1135                                    "Error starting " + impl._getLocation(), th);
1136                            }
1137                        }
1138                        // Stop the bundle if necessary.
1139                        else if (((impl.getState() == Bundle.ACTIVE)
1140                            || (impl.getState() == Bundle.STARTING))
1141                            && (impl.getStartLevel(getInitialBundleStartLevel())
1142                                > requestedLevel))
1143                        {
1144    
1145                            if (m_activeStartLevel != impl.getStartLevel(getInitialBundleStartLevel()))
1146                            {
1147                                m_activeStartLevel = impl.getStartLevel(getInitialBundleStartLevel());
1148                            }
1149    
1150                            try
1151                            {
1152                                stopBundle(impl, false);
1153                            }
1154                            catch (Throwable th)
1155                            {
1156                                fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
1157                                m_logger.log(
1158                                    Logger.LOG_ERROR,
1159                                    "Error stopping " + impl._getLocation(), th);
1160                            }
1161                        }
1162                    }
1163                    finally
1164                    {
1165                        // Always release bundle lock.
1166                        releaseBundleLock(impl);
1167                    }
1168                    // Hint to GC to collect bundle; not sure why this
1169                    // is necessary, but it appears to help.
1170                    bundles[i] = null;
1171                }
1172    
1173                m_activeStartLevel = requestedLevel;
1174    
1175            }
1176    
1177            if (getState() == Bundle.ACTIVE)
1178            {
1179                fireFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, this, null);
1180            }
1181        }
1182    
1183        /**
1184         * Returns the start level into which newly installed bundles will
1185         * be placed by default; this method implements functionality for
1186         * the Start Level service.
1187         * @return The default start level for newly installed bundles.
1188        **/
1189        int getInitialBundleStartLevel()
1190        {
1191            String s = (String) m_configMap.get(FelixConstants.BUNDLE_STARTLEVEL_PROP);
1192    
1193            if (s != null)
1194            {
1195                try
1196                {
1197                    int i = Integer.parseInt(s);
1198                    return (i > 0) ? i : FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
1199                }
1200                catch (NumberFormatException ex)
1201                {
1202                    // Ignore and return the default value.
1203                }
1204            }
1205            return FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
1206        }
1207    
1208        /**
1209         * Sets the default start level into which newly installed bundles
1210         * will be placed; this method implements functionality for the Start
1211         * Level service.
1212         * @param startLevel The new default start level for newly installed
1213         *        bundles.
1214         * @throws java.lang.IllegalArgumentException If the specified start
1215         *         level is not greater than zero.
1216         * @throws java.security.SecurityException If the caller does not
1217         *         have <tt>AdminPermission</tt>.
1218        **/
1219        void setInitialBundleStartLevel(int startLevel)
1220        {
1221            if (startLevel <= 0)
1222            {
1223                throw new IllegalArgumentException(
1224                    "Initial start level must be greater than zero.");
1225            }
1226    
1227            m_configMutableMap.put(
1228                FelixConstants.BUNDLE_STARTLEVEL_PROP, Integer.toString(startLevel));
1229        }
1230    
1231        /**
1232         * Returns the start level for the specified bundle; this method
1233         * implements functionality for the Start Level service.
1234         * @param bundle The bundle to examine.
1235         * @return The start level of the specified bundle.
1236         * @throws java.lang.IllegalArgumentException If the specified
1237         *          bundle has been uninstalled.
1238        **/
1239        int getBundleStartLevel(Bundle bundle)
1240        {
1241            if (bundle.getState() == Bundle.UNINSTALLED)
1242            {
1243                throw new IllegalArgumentException("Bundle is uninstalled.");
1244            }
1245    
1246            return ((BundleImpl) bundle).getStartLevel(getInitialBundleStartLevel());
1247        }
1248    
1249        /**
1250         * Sets the start level of the specified bundle; this method
1251         * implements functionality for the Start Level service.
1252         * @param bundle The bundle whose start level is to be modified.
1253         * @param startLevel The new start level of the specified bundle.
1254         * @throws java.lang.IllegalArgumentException If the specified
1255         *          bundle is the system bundle or if the bundle has been
1256         *          uninstalled.
1257         * @throws java.security.SecurityException If the caller does not
1258         *          have <tt>AdminPermission</tt>.
1259        **/
1260        void setBundleStartLevel(Bundle bundle, int startLevel)
1261        {
1262            // Acquire bundle lock.
1263            BundleImpl impl = (BundleImpl) bundle;
1264            try
1265            {
1266                acquireBundleLock(impl,
1267                    Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE
1268                    | Bundle.STARTING | Bundle.STOPPING);
1269            }
1270            catch (IllegalStateException ex)
1271            {
1272                fireFrameworkEvent(FrameworkEvent.ERROR, impl, ex);
1273                m_logger.log(
1274                    Logger.LOG_ERROR,
1275                    "Error locking " + impl._getLocation(), ex);
1276                return;
1277            }
1278    
1279            Throwable rethrow = null;
1280    
1281            try
1282            {
1283                if (startLevel >= 1)
1284                {
1285                    // NOTE: The start level was persistently recorded inside
1286                    // the start level impl because the spec requires it to be
1287                    // done synchronously.
1288    
1289                    try
1290                    {
1291                        // Start the bundle if necessary.
1292                        if (((impl.getPersistentState() == Bundle.ACTIVE)
1293                            || (impl.getPersistentState() == Bundle.STARTING))
1294                            && (startLevel <= getActiveStartLevel()))
1295                        {
1296    // TODO: LAZY - Not sure if this is the best way...
1297                            int options = Bundle.START_TRANSIENT;
1298                            options = (impl.getPersistentState() == Bundle.STARTING)
1299                                ? options | Bundle.START_ACTIVATION_POLICY
1300                                : options;
1301                            startBundle(impl, options);
1302                        }
1303                        // Stop the bundle if necessary.
1304                        else if (((impl.getState() == Bundle.ACTIVE)
1305                            || (impl.getState() == Bundle.STARTING))
1306                            && (startLevel > getActiveStartLevel()))
1307                        {
1308                            stopBundle(impl, false);
1309                        }
1310                    }
1311                    catch (Throwable th)
1312                    {
1313                        rethrow = th;
1314                        m_logger.log(Logger.LOG_ERROR, "Error starting/stopping bundle.", th);
1315                    }
1316                }
1317                else
1318                {
1319                    m_logger.log(Logger.LOG_WARNING, "Bundle start level must be greater than zero.");
1320                }
1321            }
1322            finally
1323            {
1324                // Always release bundle lock.
1325                releaseBundleLock(impl);
1326            }
1327    
1328            if (rethrow != null)
1329            {
1330                fireFrameworkEvent(FrameworkEvent.ERROR, bundle, rethrow);
1331            }
1332        }
1333    
1334        /**
1335         * Returns whether a bundle is persistently started; this is an
1336         * method implementation for the Start Level service.
1337         * @param bundle The bundle to examine.
1338         * @return <tt>true</tt> if the bundle is marked as persistently
1339         *          started, <tt>false</tt> otherwise.
1340         * @throws java.lang.IllegalArgumentException If the specified
1341         *          bundle has been uninstalled.
1342        **/
1343        boolean isBundlePersistentlyStarted(Bundle bundle)
1344        {
1345            if (bundle.getState() == Bundle.UNINSTALLED)
1346            {
1347                throw new IllegalArgumentException("Bundle is uninstalled.");
1348            }
1349    
1350            return (((BundleImpl) bundle).getPersistentState() == Bundle.ACTIVE)
1351                || (((BundleImpl) bundle).getPersistentState() == Bundle.STARTING);
1352        }
1353    
1354        /**
1355         * Returns whether the bundle is using its declared activation policy;
1356         * this is an method implementation for the Start Level service.
1357         * @param bundle The bundle to examine.
1358         * @return <tt>true</tt> if the bundle is using its declared activation
1359         *         policy, <tt>false</tt> otherwise.
1360         * @throws java.lang.IllegalArgumentException If the specified
1361         *          bundle has been uninstalled.
1362        **/
1363        boolean isBundleActivationPolicyUsed(Bundle bundle)
1364        {
1365            if (bundle.getState() == Bundle.UNINSTALLED)
1366            {
1367                throw new IllegalArgumentException("Bundle is uninstalled.");
1368            }
1369    
1370            return ((BundleImpl) bundle).isDeclaredActivationPolicyUsed();
1371        }
1372    
1373        //
1374        // Implementation of Bundle interface methods.
1375        //
1376    
1377        /**
1378         * Get bundle headers and resolve any localized strings from resource bundles.
1379         * @param bundle
1380         * @param locale
1381         * @return localized bundle headers dictionary.
1382        **/
1383        Dictionary getBundleHeaders(BundleImpl bundle, String locale)
1384        {
1385            return new MapToDictionary(bundle.getCurrentLocalizedHeader(locale));
1386        }
1387    
1388        /**
1389         * Implementation for Bundle.getResource().
1390        **/
1391        URL getBundleResource(BundleImpl bundle, String name)
1392        {
1393            if (bundle.getState() == Bundle.UNINSTALLED)
1394            {
1395                throw new IllegalStateException("The bundle is uninstalled.");
1396            }
1397            else if (Util.isFragment(bundle.getCurrentModule()))
1398            {
1399                return null;
1400            }
1401            return bundle.getCurrentModule().getResourceByDelegation(name);
1402        }
1403    
1404        /**
1405         * Implementation for Bundle.getResources().
1406        **/
1407        Enumeration getBundleResources(BundleImpl bundle, String name)
1408        {
1409            if (bundle.getState() == Bundle.UNINSTALLED)
1410            {
1411                throw new IllegalStateException("The bundle is uninstalled.");
1412            }
1413            else if (Util.isFragment(bundle.getCurrentModule()))
1414            {
1415                return null;
1416            }
1417            return bundle.getCurrentModule().getResourcesByDelegation(name);
1418        }
1419    
1420        /**
1421         * Implementation for Bundle.getEntry().
1422        **/
1423        URL getBundleEntry(BundleImpl bundle, String name)
1424        {
1425            if (bundle.getState() == Bundle.UNINSTALLED)
1426            {
1427                throw new IllegalStateException("The bundle is uninstalled.");
1428            }
1429            return bundle.getCurrentModule().getEntry(name);
1430        }
1431    
1432        /**
1433         * Implementation for Bundle.getEntryPaths().
1434        **/
1435        Enumeration getBundleEntryPaths(BundleImpl bundle, String path)
1436        {
1437            if (bundle.getState() == Bundle.UNINSTALLED)
1438            {
1439                throw new IllegalStateException("The bundle is uninstalled.");
1440            }
1441    
1442            // Get the entry enumeration from the module content and
1443            // create a wrapper enumeration to filter it.
1444            Enumeration enumeration = new GetEntryPathsEnumeration(bundle, path);
1445    
1446            // Return the enumeration if it has elements.
1447            return (!enumeration.hasMoreElements()) ? null : enumeration;
1448        }
1449    
1450        /**
1451         * Implementation for findEntries().
1452        **/
1453        Enumeration findBundleEntries(
1454            BundleImpl bundle, String path, String filePattern, boolean recurse)
1455        {
1456            // Try to resolve the bundle per the spec.
1457            resolveBundles(new Bundle[] { bundle });
1458    
1459            // Get the entry enumeration from the module content and
1460            // create a wrapper enumeration to filter it.
1461            Enumeration enumeration =
1462                new FindEntriesEnumeration(bundle, path, filePattern, recurse);
1463    
1464            // Return the enumeration if it has elements.
1465            return (!enumeration.hasMoreElements()) ? null : enumeration;
1466        }
1467    
1468        ServiceReference[] getBundleRegisteredServices(BundleImpl bundle)
1469        {
1470            if (bundle.getState() == Bundle.UNINSTALLED)
1471            {
1472                throw new IllegalStateException("The bundle is uninstalled.");
1473            }
1474    
1475            // Filter list of registered service references.
1476            ServiceReference[] refs = m_registry.getRegisteredServices(bundle);
1477    
1478            return refs;
1479        }
1480    
1481        ServiceReference[] getBundleServicesInUse(Bundle bundle)
1482        {
1483            // Filter list of "in use" service references.
1484            ServiceReference[] refs = m_registry.getServicesInUse(bundle);
1485    
1486            return refs;
1487        }
1488    
1489        boolean bundleHasPermission(BundleImpl bundle, Object obj)
1490        {
1491            if (bundle.getState() == Bundle.UNINSTALLED)
1492            {
1493                throw new IllegalStateException("The bundle is uninstalled.");
1494            }
1495    
1496            if (System.getSecurityManager() != null)
1497            {
1498                try
1499                {
1500                    return (obj instanceof java.security.Permission)
1501                        ? impliesBundlePermission(
1502                        (BundleProtectionDomain)
1503                        bundle.getProtectionDomain(),
1504                        (java.security.Permission) obj, true)
1505                        : false;
1506                }
1507                catch (Exception ex)
1508                {
1509                    m_logger.log(
1510                        Logger.LOG_WARNING,
1511                        "Exception while evaluating the permission.",
1512                        ex);
1513                    return false;
1514                }
1515            }
1516    
1517            return true;
1518        }
1519    
1520        /**
1521         * Implementation for Bundle.loadClass().
1522        **/
1523        Class loadBundleClass(BundleImpl bundle, String name) throws ClassNotFoundException
1524        {
1525            if (bundle.getState() == Bundle.UNINSTALLED)
1526            {
1527                throw new IllegalStateException("Bundle is uninstalled");
1528            }
1529            else if (Util.isFragment(bundle.getCurrentModule()))
1530            {
1531                throw new ClassNotFoundException("Fragments cannot load classes.");
1532            }
1533            else if (bundle.getState() == Bundle.INSTALLED)
1534            {
1535                try
1536                {
1537                    resolveBundle(bundle);
1538                }
1539                catch (BundleException ex)
1540                {
1541                    // The spec says we must fire a framework error.
1542                    fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
1543                    // Then throw a class not found exception.
1544                    throw new ClassNotFoundException(name, ex);
1545                }
1546            }
1547            return bundle.getCurrentModule().getClassByDelegation(name);
1548        }
1549    
1550        /**
1551         * Implementation for Bundle.start().
1552        **/
1553        void startBundle(BundleImpl bundle, int options) throws BundleException
1554        {
1555            // CONCURRENCY NOTE:
1556            // We will first acquire the bundle lock for the specific bundle
1557            // as long as the bundle is INSTALLED, RESOLVED, or ACTIVE. If this
1558            // bundle is not yet resolved, then it will be resolved too. In
1559            // that case, the global lock will be acquired to make sure no
1560            // bundles can be installed or uninstalled during the resolve.
1561    
1562            int eventType;
1563    
1564            // Acquire bundle lock.
1565            try
1566            {
1567                acquireBundleLock(bundle,
1568                    Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE);
1569            }
1570            catch (IllegalStateException ex)
1571            {
1572                if (bundle.getState() == Bundle.UNINSTALLED)
1573                {
1574                    throw new IllegalStateException("Cannot start an uninstalled bundle.");
1575                }
1576                else
1577                {
1578                    throw new BundleException(
1579                        "Bundle " + bundle
1580                        + " cannot be started, since it is either starting or stopping.");
1581                }
1582            }
1583    
1584            // Record whether the bundle is using its declared activation policy.
1585            boolean wasDeferred = bundle.isDeclaredActivationPolicyUsed()
1586                && (bundle.getCurrentModule().getDeclaredActivationPolicy() == IModule.LAZY_ACTIVATION);
1587            bundle.setDeclaredActivationPolicyUsed(
1588                (options & Bundle.START_ACTIVATION_POLICY) != 0);
1589    
1590            BundleException rethrow = null;
1591            try
1592            {
1593                // The spec doesn't say whether it is possible to start an extension
1594                // We just do nothing
1595                if (bundle.isExtension())
1596                {
1597                    return;
1598                }
1599    
1600                // As per the OSGi spec, fragment bundles can not be started and must
1601                // throw a BundleException when there is an attempt to start one.
1602                if (Util.isFragment(bundle.getCurrentModule()))
1603                {
1604                    throw new BundleException("Fragment bundles can not be started.");
1605                }
1606    
1607                // Set and save the bundle's persistent state to active
1608                // if we are supposed to record state change.
1609                if ((options & Bundle.START_TRANSIENT) == 0)
1610                {
1611                    if ((options & Bundle.START_ACTIVATION_POLICY) != 0)
1612                    {
1613                        bundle.setPersistentStateStarting();
1614                    }
1615                    else
1616                    {
1617                        bundle.setPersistentStateActive();
1618                    }
1619                }
1620    
1621                // Check to see if the bundle's start level is greater than the
1622                // the framework's active start level.
1623                if (bundle.getStartLevel(getInitialBundleStartLevel()) > getActiveStartLevel())
1624                {
1625                    // Throw an exception for transient starts.
1626                    if ((options & Bundle.START_TRANSIENT) != 0)
1627                    {
1628                        throw new BundleException(
1629                            "Cannot start bundle " + bundle + " because its start level is "
1630                            + bundle.getStartLevel(getInitialBundleStartLevel())
1631                            + ", which is greater than the framework's start level of "
1632                            + getActiveStartLevel() + ".");
1633                    }
1634                    // Ignore persistent starts.
1635                    return;
1636                }
1637    
1638                switch (bundle.getState())
1639                {
1640                    case Bundle.UNINSTALLED:
1641                        throw new IllegalStateException("Cannot start an uninstalled bundle.");
1642                    case Bundle.STARTING:
1643                        if (!wasDeferred)
1644                        {
1645                            throw new BundleException(
1646                                "Bundle " + bundle
1647                                + " cannot be started, since it is starting.");
1648                        }
1649                        break;
1650                    case Bundle.STOPPING:
1651                        throw new BundleException(
1652                            "Bundle " + bundle
1653                            + " cannot be started, since it is stopping.");
1654                    case Bundle.ACTIVE:
1655                        return;
1656                    case Bundle.INSTALLED:
1657                        resolveBundle(bundle);
1658                        // No break.
1659                    case Bundle.RESOLVED:
1660                        // Set the bundle's context.
1661                        bundle.setBundleContext(new BundleContextImpl(m_logger, this, bundle));
1662                        // At this point, no matter if the bundle's activation policy is
1663                        // eager or deferred, we need to set the bundle's state to STARTING.
1664                        // We don't fire a BundleEvent here for this state change, since
1665                        // STARTING events are only fired if we are invoking the activator,
1666                        // which we may not do if activation is deferred.
1667                        setBundleStateAndNotify(bundle, Bundle.STARTING);
1668                        break;
1669                }
1670    
1671                // If the bundle's activation policy is eager or activation has already
1672                // been triggered, then activate the bundle immediately.
1673                if (!bundle.isDeclaredActivationPolicyUsed()
1674                    || (bundle.getCurrentModule().getDeclaredActivationPolicy() != IModule.LAZY_ACTIVATION)
1675                    || ((ModuleImpl) bundle.getCurrentModule()).isActivationTriggered())
1676                {
1677                    // Record the event type for the final event and activate.
1678                    eventType = BundleEvent.STARTED;
1679                    // Note that the STARTING event is thrown in the activateBundle() method.
1680                    try
1681                    {
1682                        activateBundle(bundle, false);
1683                    }
1684                    catch (BundleException ex)
1685                    {
1686                        rethrow = ex;
1687                    }
1688                }
1689                // Otherwise, defer bundle activation.
1690                else
1691                {
1692                    // Record the event type for the final event.
1693                    eventType = BundleEvent.LAZY_ACTIVATION;
1694                }
1695    
1696                // We still need to fire the STARTED event, but we will do
1697                // it later so we can release the bundle lock.
1698            }
1699            finally
1700            {
1701                // Release bundle lock.
1702                releaseBundleLock(bundle);
1703            }
1704    
1705            // If there was no exception, then we should fire the STARTED
1706            // or LAZY_ACTIVATION event here without holding the lock. Otherwise,
1707            // fire STOPPED and rethrow exception.
1708            if (rethrow == null)
1709            {
1710                fireBundleEvent(eventType, bundle);
1711            }
1712            else
1713            {
1714                fireBundleEvent(BundleEvent.STOPPED, bundle);
1715                throw rethrow;
1716            }
1717        }
1718    
1719        void activateBundle(BundleImpl bundle, boolean fireEvent) throws BundleException
1720        {
1721            // CONCURRENCY NOTE:
1722            // We will first acquire the bundle lock for the specific bundle
1723            // as long as the bundle is INSTALLED, RESOLVED, or ACTIVE. If this
1724            // bundle is not yet resolved, then it will be resolved too. In
1725            // that case, the global lock will be acquired to make sure no
1726            // bundles can be installed or uninstalled during the resolve.
1727    
1728            // Acquire bundle lock.
1729            try
1730            {
1731                acquireBundleLock(bundle, Bundle.STARTING | Bundle.ACTIVE);
1732            }
1733            catch (IllegalStateException ex)
1734            {
1735                throw new IllegalStateException(
1736                    "Activation only occurs for bundles in STARTING state.");
1737            }
1738    
1739            try
1740            {
1741                // If the bundle is already active or its start level is not met,
1742                // simply return.
1743                if ((bundle.getState() == Bundle.ACTIVE) ||
1744                    (bundle.getStartLevel(getInitialBundleStartLevel()) > getActiveStartLevel()))
1745                {
1746                    return;
1747                }
1748    
1749                // Fire STARTING event to signify call to bundle activator.
1750                fireBundleEvent(BundleEvent.STARTING, bundle);
1751    
1752                try
1753                {
1754                    // Set the bundle's activator.
1755                    bundle.setActivator(createBundleActivator(bundle));
1756    
1757                    // Activate the bundle if it has an activator.
1758                    if (bundle.getActivator() != null)
1759                    {
1760                        m_secureAction.startActivator(
1761                            bundle.getActivator(), bundle._getBundleContext());
1762                    }
1763    
1764                    setBundleStateAndNotify(bundle, Bundle.ACTIVE);
1765    
1766                    // We still need to fire the STARTED event, but we will do
1767                    // it later so we can release the bundle lock.
1768                }
1769                catch (Throwable th)
1770                {
1771                    // Spec says we must fire STOPPING event.
1772                    fireBundleEvent(BundleEvent.STOPPING, bundle);
1773    
1774                    // If there was an error starting the bundle,
1775                    // then reset its state to RESOLVED.
1776                    setBundleStateAndNotify(bundle, Bundle.RESOLVED);
1777    
1778                    // Clean up the bundle activator
1779                    bundle.setActivator(null);
1780    
1781                    // Unregister any services offered by this bundle.
1782                    m_registry.unregisterServices(bundle);
1783    
1784                    // Release any services being used by this bundle.
1785                    m_registry.ungetServices(bundle);
1786    
1787                    // Remove any listeners registered by this bundle.
1788                    m_dispatcher.removeListeners(bundle);
1789    
1790                    // Clean up the bundle context.
1791                    ((BundleContextImpl) bundle._getBundleContext()).invalidate();
1792                    bundle.setBundleContext(null);
1793    
1794                    // The spec says to expect BundleException or
1795                    // SecurityException, so rethrow these exceptions.
1796                    if (th instanceof BundleException)
1797                    {
1798                        throw (BundleException) th;
1799                    }
1800                    else if ((System.getSecurityManager() != null) &&
1801                        (th instanceof java.security.PrivilegedActionException))
1802                    {
1803                        th = ((java.security.PrivilegedActionException) th).getException();
1804                    }
1805    
1806                    // Rethrow all other exceptions as a BundleException.
1807                    throw new BundleException("Activator start error in bundle " + bundle + ".", th);
1808                }
1809            }
1810            finally
1811            {
1812                // Release bundle lock.
1813                releaseBundleLock(bundle);
1814            }
1815    
1816            // If there was no exception, then we should fire the STARTED
1817            // event here without holding the lock if specified.
1818            // TODO: LAZY - It would be nice to figure out how to do this without
1819            //       duplicating code; this method is called from two different
1820            //       places -- one fires the event itself the other one needs it.
1821            if (fireEvent)
1822            {
1823                fireBundleEvent(BundleEvent.STARTED, bundle);
1824            }
1825        }
1826    
1827        void updateBundle(BundleImpl bundle, InputStream is)
1828            throws BundleException
1829        {
1830            // Acquire bundle lock.
1831            try
1832            {
1833                acquireBundleLock(bundle, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE);
1834            }
1835            catch (IllegalStateException ex)
1836            {
1837                if (bundle.getState() == Bundle.UNINSTALLED)
1838                {
1839                    throw new IllegalStateException("Cannot update an uninstalled bundle.");
1840                }
1841                else
1842                {
1843                    throw new BundleException(
1844                        "Bundle " + bundle
1845                        + " cannot be update, since it is either starting or stopping.");
1846                }
1847            }
1848    
1849            // We must release the lock and close the input stream, so do both
1850            // in a finally block.
1851            try
1852            {
1853                // Variable to indicate whether bundle is active or not.
1854                Throwable rethrow = null;
1855    
1856                final int oldState = bundle.getState();
1857    
1858                // First get the update-URL from our header.
1859                String updateLocation = (String)
1860                    bundle.getCurrentModule().getHeaders().get(
1861                        Constants.BUNDLE_UPDATELOCATION);
1862    
1863                // If no update location specified, use original location.
1864                if (updateLocation == null)
1865                {
1866                    updateLocation = bundle._getLocation();
1867                }
1868    
1869                // Stop the bundle if it is active, but do not change its
1870                // persistent state.
1871                if (oldState == Bundle.ACTIVE)
1872                {
1873                    stopBundle(bundle, false);
1874                }
1875    
1876                try
1877                {
1878                    // Revising the bundle creates a new module, which modifies
1879                    // the global state, so we need to acquire the global lock
1880                    // before revising.
1881                    boolean locked = acquireGlobalLock();
1882                    if (!locked)
1883                    {
1884                        throw new BundleException(
1885                            "Cannot acquire global lock to update the bundle.");
1886                    }
1887                    boolean wasExtension = bundle.isExtension();
1888                    try
1889                    {
1890    // REFACTOR - This adds the module to the resolver state, but should we do the
1891    //            security check first?
1892                        bundle.revise(updateLocation, is);
1893                    }
1894                    finally
1895                    {
1896                        // Always release the global lock.
1897                        releaseGlobalLock();
1898                    }
1899    
1900                    // Verify updated bundle.
1901                    try
1902                    {
1903                        Object sm = System.getSecurityManager();
1904    
1905                        if (sm != null)
1906                        {
1907                            ((SecurityManager) sm).checkPermission(
1908                                new AdminPermission(bundle, AdminPermission.LIFECYCLE));
1909                        }
1910    
1911                        // If this is an update from a normal to an extension bundle
1912                        // then attach the extension
1913                        if (!wasExtension && bundle.isExtension())
1914                        {
1915                            m_extensionManager.addExtensionBundle(this, bundle);
1916    // TODO: REFACTOR - Perhaps we could move this into extension manager.
1917                            m_resolverState.refreshSystemBundleModule(m_extensionManager.getModule());
1918    // TODO: REFACTOR - Not clear why this is here. We should look at all of these steps more closely.
1919                            setBundleStateAndNotify(bundle, Bundle.RESOLVED);
1920                        }
1921                        else if (wasExtension)
1922                        {
1923                            setBundleStateAndNotify(bundle, Bundle.INSTALLED);
1924                        }
1925                    }
1926                    catch (Throwable ex)
1927                    {
1928                        try
1929                        {
1930                            bundle.rollbackRevise();
1931                        }
1932                        catch (Exception busted)
1933                        {
1934                            m_logger.log(Logger.LOG_ERROR, "Unable to rollback.", busted);
1935                        }
1936    
1937                        throw ex;
1938                    }
1939                }
1940                catch (Throwable ex)
1941                {
1942                    m_logger.log(Logger.LOG_ERROR, "Unable to update the bundle.", ex);
1943                    rethrow = ex;
1944                }
1945    
1946                // Set new state, mark as needing a refresh, and fire updated event
1947                // if successful.
1948                if (rethrow == null)
1949                {
1950                    bundle.setLastModified(System.currentTimeMillis());
1951    
1952                    if (!bundle.isExtension())
1953                    {
1954                        setBundleStateAndNotify(bundle, Bundle.INSTALLED);
1955                    }
1956                    else
1957                    {
1958                        m_extensionManager.startExtensionBundle(this, bundle);
1959                    }
1960    
1961                    fireBundleEvent(BundleEvent.UNRESOLVED, bundle);
1962    
1963                    fireBundleEvent(BundleEvent.UPDATED, bundle);
1964    
1965                    // Acquire global lock to check if we should auto-refresh.
1966                    boolean locked = acquireGlobalLock();
1967                    // If we did not get the global lock, then do not try to
1968                    // auto-refresh.
1969                    if (locked)
1970                    {
1971                        try
1972                        {
1973                            if (!bundle.isUsed() && !bundle.isExtension())
1974                            {
1975                                try
1976                                {
1977                                    refreshPackages(new BundleImpl[] { bundle });
1978                                }
1979                                catch (Exception ex)
1980                                {
1981                                    m_logger.log(
1982                                        Logger.LOG_ERROR,
1983                                        "Unable to immediately purge the bundle revisions.", ex);
1984                                }
1985                            }
1986                        }
1987                        finally
1988                        {
1989                            // Always release the global lock.
1990                            releaseGlobalLock();
1991                        }
1992                    }
1993                }
1994    
1995                // If the old state was active, but the new module is a fragment,
1996                // then mark the persistent state to inactive.
1997                if ((oldState == Bundle.ACTIVE) && Util.isFragment(bundle.getCurrentModule()))
1998                {
1999                    bundle.setPersistentStateInactive();
2000                    m_logger.log(Logger.LOG_WARNING,
2001                        "Previously active bundle was updated to a fragment, resetting state to inactive: "
2002                        + bundle);
2003                }
2004                // Otherwise, restart the bundle if it was previously active,
2005                // but do not change its persistent state.
2006                else if (oldState == Bundle.ACTIVE)
2007                {
2008                    startBundle(bundle, Bundle.START_TRANSIENT);
2009                }
2010    
2011                // If update failed, rethrow exception.
2012                if (rethrow != null)
2013                {
2014                    if (rethrow instanceof AccessControlException)
2015                    {
2016                        throw (AccessControlException) rethrow;
2017                    }
2018                    else
2019                    {
2020                        throw new BundleException("Update of bundle " + bundle + " failed.", rethrow);
2021                    }
2022                }
2023            }
2024            finally
2025            {
2026                // Close the input stream.
2027                try
2028                {
2029                    if (is != null) is.close();
2030                }
2031                catch (Exception ex)
2032                {
2033                    m_logger.log(Logger.LOG_ERROR, "Unable to close input stream.", ex);
2034                }
2035    
2036                // Release bundle lock.
2037                releaseBundleLock(bundle);
2038            }
2039        }
2040    
2041        void stopBundle(BundleImpl bundle, boolean record)
2042            throws BundleException
2043        {
2044            // Acquire bundle lock.
2045            try
2046            {
2047                acquireBundleLock(bundle,
2048                    Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE);
2049            }
2050            catch (IllegalStateException ex)
2051            {
2052                if (bundle.getState() == Bundle.UNINSTALLED)
2053                {
2054                    throw new IllegalStateException("Cannot stop an uninstalled bundle.");
2055                }
2056                else
2057                {
2058                    throw new BundleException(
2059                        "Bundle " + bundle
2060                        + " cannot be stopped since it is already stopping.");
2061                }
2062            }
2063    
2064            try
2065            {
2066                Throwable rethrow = null;
2067    
2068                // Set the bundle's persistent state to inactive if necessary.
2069                if (record)
2070                {
2071                    bundle.setPersistentStateInactive();
2072                }
2073    
2074                // If the bundle is not persistently started, then we
2075                // need to reset the activation policy flag, since it
2076                // does not persist across persistent stops or transient
2077                // stops.
2078                if (!isBundlePersistentlyStarted(bundle))
2079                {
2080                    bundle.setDeclaredActivationPolicyUsed(false);
2081                }
2082    
2083                // As per the OSGi spec, fragment bundles can not be stopped and must
2084                // throw a BundleException when there is an attempt to stop one.
2085                if (Util.isFragment(bundle.getCurrentModule()))
2086                {
2087                    throw new BundleException("Fragment bundles can not be stopped: " + bundle);
2088                }
2089    
2090                boolean wasActive = false;
2091                switch (bundle.getState())
2092                {
2093                    case Bundle.UNINSTALLED:
2094                        throw new IllegalStateException("Cannot stop an uninstalled bundle.");
2095                    case Bundle.STARTING:
2096                        if (bundle.isDeclaredActivationPolicyUsed()
2097                            && bundle.getCurrentModule().getDeclaredActivationPolicy() != IModule.LAZY_ACTIVATION)
2098                        {
2099                            throw new BundleException(
2100                                "Stopping a starting or stopping bundle is currently not supported.");
2101                        }
2102                        break;
2103                    case Bundle.STOPPING:
2104                        throw new BundleException(
2105                            "Stopping a starting or stopping bundle is currently not supported.");
2106                    case Bundle.INSTALLED:
2107                    case Bundle.RESOLVED:
2108                        return;
2109                    case Bundle.ACTIVE:
2110                        wasActive = true;
2111                        break;
2112                }
2113    
2114                // At this point, no matter if the bundle's activation policy is
2115                // eager or deferred, we need to set the bundle's state to STOPPING
2116                // and fire the STOPPING event.
2117                setBundleStateAndNotify(bundle, Bundle.STOPPING);
2118                fireBundleEvent(BundleEvent.STOPPING, bundle);
2119    
2120                // If the bundle was active, then invoke the activator stop() method
2121                // or if we are stopping the system bundle.
2122                if ((wasActive) || (bundle.getBundleId() == 0))
2123                {
2124                    try
2125                    {
2126                        if (bundle.getActivator() != null)
2127                        {
2128                            m_secureAction.stopActivator(bundle.getActivator(), bundle._getBundleContext());
2129                        }
2130                    }
2131                    catch (Throwable th)
2132                    {
2133                        m_logger.log(Logger.LOG_ERROR, "Error stopping bundle.", th);
2134                        rethrow = th;
2135                    }
2136                }
2137    
2138                // Do not clean up after the system bundle since it will
2139                // clean up after itself.
2140                if (bundle.getBundleId() != 0)
2141                {
2142                    // Clean up the bundle activator.
2143                    bundle.setActivator(null);
2144    
2145                    // Unregister any services offered by this bundle.
2146                    m_registry.unregisterServices(bundle);
2147    
2148                    // Release any services being used by this bundle.
2149                    m_registry.ungetServices(bundle);
2150    
2151                    // The spec says that we must remove all event
2152                    // listeners for a bundle when it is stopped.
2153                    m_dispatcher.removeListeners(bundle);
2154    
2155                    // Clean up the bundle context.
2156                    ((BundleContextImpl) bundle._getBundleContext()).invalidate();
2157                    bundle.setBundleContext(null);
2158    
2159                    setBundleStateAndNotify(bundle, Bundle.RESOLVED);
2160    
2161                    // We still need to fire the STOPPED event, but we will do
2162                    // it later so we can release the bundle lock.
2163                }
2164    
2165                // Throw activator error if there was one.
2166                if (rethrow != null)
2167                {
2168                    // The spec says to expect BundleException or
2169                    // SecurityException, so rethrow these exceptions.
2170                    if (rethrow instanceof BundleException)
2171                    {
2172                        throw (BundleException) rethrow;
2173                    }
2174                    else if ((System.getSecurityManager() != null) &&
2175                        (rethrow instanceof java.security.PrivilegedActionException))
2176                    {
2177                        rethrow = ((java.security.PrivilegedActionException) rethrow).getException();
2178                    }
2179    
2180                    // Rethrow all other exceptions as a BundleException.
2181                    throw new BundleException(
2182                        "Activator stop error in bundle " + bundle + ".", rethrow);
2183                }
2184            }
2185            finally
2186            {
2187                // Always release bundle lock.
2188                releaseBundleLock(bundle);
2189            }
2190    
2191            // If there was no exception, then we should fire the STOPPED event
2192            // here without holding the lock.
2193            fireBundleEvent(BundleEvent.STOPPED, bundle);
2194        }
2195    
2196        void uninstallBundle(BundleImpl bundle) throws BundleException
2197        {
2198            // Acquire bundle lock.
2199            try
2200            {
2201                acquireBundleLock(bundle,
2202                    Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE);
2203            }
2204            catch (IllegalStateException ex)
2205            {
2206                if (bundle.getState() == Bundle.UNINSTALLED)
2207                {
2208                    throw new IllegalStateException("Cannot uninstall an uninstalled bundle.");
2209                }
2210                else
2211                {
2212                    throw new BundleException(
2213                        "Bundle " + bundle
2214                        + " cannot be uninstalled since it is stopping.");
2215                }
2216            }
2217    
2218            try
2219            {
2220                // The spec says that uninstall should always succeed, so
2221                // catch an exception here if stop() doesn't succeed and
2222                // rethrow it at the end.
2223                if (!bundle.isExtension() && (bundle.getState() == Bundle.ACTIVE))
2224                {
2225                    try
2226                    {
2227                        stopBundle(bundle, true);
2228                    }
2229                    catch (BundleException ex)
2230                    {
2231                        fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
2232                    }
2233                }
2234    
2235                // Remove the bundle from the installed map.
2236                BundleImpl target = null;
2237                synchronized (m_installedBundleLock_Priority2)
2238                {
2239                    target = (BundleImpl) m_installedBundleMap.remove(bundle._getLocation());
2240                    m_installedBundleIndex.remove(new Long(target.getBundleId()));
2241                }
2242    
2243                // Finally, put the uninstalled bundle into the
2244                // uninstalled list for subsequent refreshing.
2245                if (target != null)
2246                {
2247                    // Set the bundle's persistent state to uninstalled.
2248                    bundle.setPersistentStateUninstalled();
2249    
2250                    // Put bundle in uninstalled bundle array.
2251                    rememberUninstalledBundle(bundle);
2252                }
2253                else
2254                {
2255                    m_logger.log(
2256                        Logger.LOG_ERROR, "Unable to remove bundle from installed map!");
2257                }
2258    
2259                setBundleStateAndNotify(bundle, Bundle.INSTALLED);
2260    
2261                // Unfortunately, fire UNRESOLVED event while holding the lock,
2262                // since we still need to change the bundle state.
2263                fireBundleEvent(BundleEvent.UNRESOLVED, bundle);
2264    
2265                // Set state to uninstalled.
2266                setBundleStateAndNotify(bundle, Bundle.UNINSTALLED);
2267                bundle.setLastModified(System.currentTimeMillis());
2268    
2269                // If this bundle is a fragment, unmerge it from any
2270                // unresolved hosts.
2271                bundle.cleanAfterUninstall();
2272            }
2273            finally
2274            {
2275                // Always release bundle lock.
2276                releaseBundleLock(bundle);
2277            }
2278    
2279            // Fire UNINSTALLED event without holding the lock.
2280            fireBundleEvent(BundleEvent.UNINSTALLED, bundle);
2281    
2282            // Acquire global lock to check if we should auto-refresh.
2283            boolean locked = acquireGlobalLock();
2284            if (locked)
2285            {
2286                try
2287                {
2288                    // If the bundle is not used by anyone, then garbage
2289                    // collect it now.
2290                    if (!bundle.isUsed())
2291                    {
2292                        try
2293                        {
2294                            refreshPackages(new BundleImpl[] { bundle });
2295                        }
2296                        catch (Exception ex)
2297                        {
2298                            m_logger.log(
2299                                Logger.LOG_ERROR,
2300                                "Unable to immediately garbage collect the bundle.", ex);
2301                        }
2302                    }
2303                }
2304                finally
2305                {
2306                    // Always release the global lock.
2307                    releaseGlobalLock();
2308                }
2309            }
2310        }
2311    
2312        //
2313        // Implementation of BundleContext interface methods.
2314        //
2315    
2316        /**
2317         * Implementation for BundleContext.getProperty(). Returns
2318         * environment property associated with the framework.
2319         *
2320         * @param key The name of the property to retrieve.
2321         * @return The value of the specified property or null.
2322        **/
2323        String getProperty(String key)
2324        {
2325            // First, check the config properties.
2326            String val = (String) m_configMap.get(key);
2327            // If not found, then try the system properties.
2328            return (val == null) ? System.getProperty(key) : val;
2329        }
2330    
2331        Bundle installBundle(String location, InputStream is)
2332            throws BundleException
2333        {
2334            return installBundle(-1, location, null, is);
2335        }
2336    
2337        private Bundle installBundle(long id, String location, BundleArchive ba, InputStream is)
2338            throws BundleException
2339        {
2340            BundleImpl bundle = null;
2341    
2342            // Acquire an install lock.
2343            acquireInstallLock(location);
2344    
2345            try
2346            {
2347                // Check to see if the framework is still running;
2348                if ((getState() == Bundle.STOPPING) ||
2349                    (getState() == Bundle.UNINSTALLED))
2350                {
2351                    throw new BundleException("The framework has been shutdown.");
2352                }
2353    
2354                // If bundle location is already installed, then
2355                // return it as required by the OSGi specification.
2356                bundle = (BundleImpl) getBundle(location);
2357                if (bundle != null)
2358                {
2359                    return bundle;
2360                }
2361    
2362                // Determine if this is a new or existing bundle.
2363                boolean isNew = (ba == null);
2364    
2365                // If the bundle is new we must cache its JAR file.
2366                if (isNew)
2367                {
2368                    // First generate an identifier for it.
2369                    id = getNextId();
2370    
2371                    try
2372                    {
2373                        // Add the bundle to the cache.
2374                        ba = m_cache.create(id, location, is);
2375                    }
2376                    catch (Exception ex)
2377                    {
2378                        throw new BundleException(
2379                            "Unable to cache bundle: " + location, ex);
2380                    }
2381                    finally
2382                    {
2383                        try
2384                        {
2385                            if (is != null) is.close();
2386                        }
2387                        catch (IOException ex)
2388                        {
2389                            m_logger.log(
2390                                Logger.LOG_ERROR,
2391                                "Unable to close input stream.", ex);
2392                        }
2393                    }
2394                }
2395                else
2396                {
2397                    // If the bundle we are installing is not new,
2398                    // then try to purge old revisions before installing
2399                    // it; this is done just in case a "refresh"
2400                    // didn't occur last session...this would only be
2401                    // due to an error or system crash.
2402                    try
2403                    {
2404                        if (ba.getRevisionCount() > 1)
2405                        {
2406                            ba.purge();
2407                        }
2408                    }
2409                    catch (Exception ex)
2410                    {
2411                        m_logger.log(
2412                            Logger.LOG_ERROR,
2413                            "Could not purge bundle.", ex);
2414                    }
2415                }
2416    
2417                try
2418                {
2419                    // Acquire the global lock to create the bundle,
2420                    // since this impacts the global state.
2421                    boolean locked = acquireGlobalLock();
2422                    if (!locked)
2423                    {
2424                        throw new BundleException(
2425                            "Unable to acquire the global lock to install the bundle.");
2426                    }
2427                    try
2428                    {
2429                        bundle = new BundleImpl(this, ba);
2430                    }
2431                    finally
2432                    {
2433                        // Always release the global lock.
2434                        releaseGlobalLock();
2435                    }
2436    
2437                    if (!bundle.isExtension())
2438                    {
2439                        Object sm = System.getSecurityManager();
2440                        if (sm != null)
2441                        {
2442                            ((SecurityManager) sm).checkPermission(
2443                                new AdminPermission(bundle, AdminPermission.LIFECYCLE));
2444                        }
2445                    }
2446                    else
2447                    {
2448                        m_extensionManager.addExtensionBundle(this, bundle);
2449                        m_resolverState.refreshSystemBundleModule(m_extensionManager.getModule());
2450                    }
2451                }
2452                catch (Throwable ex)
2453                {
2454                    // If the bundle is new, then remove it from the cache.
2455                    // TODO: FRAMEWORK - Perhaps it should be removed if it is not new too.
2456                    if (isNew)
2457                    {
2458                        try
2459                        {
2460                            if (bundle != null)
2461                            {
2462                                bundle.closeAndDelete();
2463                            }
2464                            else if (ba != null)
2465                            {
2466                                ba.closeAndDelete();
2467                            }
2468                        }
2469                        catch (Exception ex1)
2470                        {
2471                            m_logger.log(
2472                                Logger.LOG_ERROR,
2473                                "Could not remove from cache.", ex1);
2474                        }
2475                    }
2476    
2477                    if (ex instanceof BundleException)
2478                    {
2479                        throw (BundleException) ex;
2480                    }
2481                    else if (ex instanceof AccessControlException)
2482                    {
2483                        throw (AccessControlException) ex;
2484                    }
2485                    else
2486                    {
2487                        throw new BundleException("Could not create bundle object.", ex);
2488                    }
2489                }
2490    
2491                // If the bundle is new, then set its start level; existing
2492                // bundles already have their start level set.
2493                if (isNew)
2494                {
2495                    // This will persistently set the bundle's start level.
2496                    bundle.setStartLevel(getInitialBundleStartLevel());
2497                    bundle.setLastModified(System.currentTimeMillis());
2498                }
2499    
2500                synchronized (m_installedBundleLock_Priority2)
2501                {
2502                    m_installedBundleMap.put(location, bundle);
2503                    m_installedBundleIndex.put(new Long(bundle.getBundleId()), bundle);
2504                }
2505    
2506                if (bundle.isExtension())
2507                {
2508                    m_extensionManager.startExtensionBundle(this, bundle);
2509                }
2510            }
2511            finally
2512            {
2513                // Always release install lock.
2514                releaseInstallLock(location);
2515    
2516                // Always try to close the input stream.
2517                try
2518                {
2519                    if (is != null) is.close();
2520                }
2521                catch (IOException ex)
2522                {
2523                    m_logger.log(
2524                        Logger.LOG_ERROR,
2525                        "Unable to close input stream.", ex);
2526                    // Not much else we can do.
2527                }
2528            }
2529    
2530            // Fire bundle event.
2531            fireBundleEvent(BundleEvent.INSTALLED, bundle);
2532    
2533            // Return new bundle.
2534            return bundle;
2535        }
2536    
2537        /**
2538         * Retrieves a bundle from its location.
2539         *
2540         * @param location The location of the bundle to retrieve.
2541         * @return The bundle associated with the location or null if there
2542         *         is no bundle associated with the location.
2543        **/
2544        Bundle getBundle(String location)
2545        {
2546            synchronized (m_installedBundleLock_Priority2)
2547            {
2548                return (Bundle) m_installedBundleMap.get(location);
2549            }
2550        }
2551    
2552        /**
2553         * Implementation for BundleContext.getBundle(). Retrieves a
2554         * bundle from its identifier.
2555         *
2556         * @param id The identifier of the bundle to retrieve.
2557         * @return The bundle associated with the identifier or null if there
2558         *         is no bundle associated with the identifier.
2559        **/
2560        Bundle getBundle(long id)
2561        {
2562            synchronized (m_installedBundleLock_Priority2)
2563            {
2564                BundleImpl bundle = (BundleImpl) m_installedBundleIndex.get(new Long(id));
2565                if (bundle != null)
2566                {
2567                    return bundle;
2568                }
2569            }
2570    
2571            synchronized (m_uninstalledBundlesLock_Priority3)
2572            {
2573                for (int i = 0;
2574                    (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
2575                    i++)
2576                {
2577                    if (m_uninstalledBundles[i].getBundleId() == id)
2578                    {
2579                        return m_uninstalledBundles[i];
2580                    }
2581                }
2582            }
2583    
2584            return null;
2585        }
2586    
2587        /**
2588         * Implementation for BundleContext.getBundles(). Retrieves
2589         * all installed bundles.
2590         *
2591         * @return An array containing all installed bundles or null if
2592         *         there are no installed bundles.
2593        **/
2594        Bundle[] getBundles()
2595        {
2596            synchronized (m_installedBundleLock_Priority2)
2597            {
2598                if (m_installedBundleMap.size() == 0)
2599                {
2600                    return null;
2601                }
2602    
2603                return (Bundle[]) m_installedBundleIndex.values().toArray(
2604                    new Bundle[m_installedBundleIndex.size()]);
2605            }
2606        }
2607    
2608        void addBundleListener(Bundle bundle, BundleListener l)
2609        {
2610            m_dispatcher.addListener(bundle, BundleListener.class, l, null);
2611        }
2612    
2613        void removeBundleListener(Bundle bundle, BundleListener l)
2614        {
2615            m_dispatcher.removeListener(bundle, BundleListener.class, l);
2616        }
2617    
2618        /**
2619         * Implementation for BundleContext.addServiceListener().
2620         * Adds service listener to the listener list so that is
2621         * can listen for <code>ServiceEvent</code>s.
2622         *
2623         * @param bundle The bundle that registered the listener.
2624         * @param l The service listener to add to the listener list.
2625         * @param f The filter for the listener; may be null.
2626        **/
2627        void addServiceListener(Bundle bundle, ServiceListener l, String f)
2628            throws InvalidSyntaxException
2629        {
2630            Filter oldFilter = m_dispatcher.addListener(
2631                bundle, ServiceListener.class, l, (f == null) ? null : FrameworkUtil.createFilter(f));
2632    
2633            List listenerHooks = m_registry.getListenerHooks();
2634            if (oldFilter != null)
2635            {
2636                final Collection removed = Collections.singleton(
2637                    new ListenerHookInfoImpl(((BundleImpl) bundle)._getBundleContext(), l, oldFilter.toString(), true));
2638                InvokeHookCallback removedCallback = new ListenerHookRemovedCallback(removed);
2639                for (int i = 0; i < listenerHooks.size(); i++)
2640                {
2641                    m_registry.invokeHook((ServiceReference) listenerHooks.get(i), this, removedCallback);
2642                }
2643            }
2644    
2645            // Invoke the ListenerHook.added() on all hooks.
2646            final Collection added = Collections.singleton(
2647                new ListenerHookInfoImpl(((BundleImpl) bundle)._getBundleContext(), l, f, false));
2648            InvokeHookCallback addedCallback = new InvokeHookCallback()
2649            {
2650                public void invokeHook(Object hook)
2651                {
2652                    ((ListenerHook) hook).added(added);
2653                }
2654            };
2655            for (int i = 0; i < listenerHooks.size(); i++)
2656            {
2657                m_registry.invokeHook((ServiceReference) listenerHooks.get(i), this, addedCallback);
2658            }
2659        }
2660    
2661        /**
2662         * Implementation for BundleContext.removeServiceListener().
2663         * Removes service listeners from the listener list.
2664         *
2665         * @param bundle The context bundle of the listener
2666         * @param l The service listener to remove from the listener list.
2667        **/
2668        void removeServiceListener(Bundle bundle, ServiceListener l)
2669        {
2670            ListenerHook.ListenerInfo listener =
2671                m_dispatcher.removeListener(bundle, ServiceListener.class, l);
2672    
2673            if (listener != null)
2674            {
2675                // Invoke the ListenerHook.removed() on all hooks.
2676                List listenerHooks = m_registry.getListenerHooks();
2677                Collection c = Collections.singleton(listener);
2678                InvokeHookCallback callback = new ListenerHookRemovedCallback(c);
2679                for (int i = 0; i < listenerHooks.size(); i++)
2680                {
2681                    m_registry.invokeHook((ServiceReference) listenerHooks.get(i), this, callback);
2682                }
2683            }
2684        }
2685    
2686        void addFrameworkListener(Bundle bundle, FrameworkListener l)
2687        {
2688            m_dispatcher.addListener(bundle, FrameworkListener.class, l, null);
2689        }
2690    
2691        void removeFrameworkListener(Bundle bundle, FrameworkListener l)
2692        {
2693            m_dispatcher.removeListener(bundle, FrameworkListener.class, l);
2694        }
2695    
2696        /**
2697         * Implementation for BundleContext.registerService(). Registers
2698         * a service for the specified bundle bundle.
2699         *
2700         * @param classNames A string array containing the names of the classes
2701         *                under which the new service is available.
2702         * @param svcObj The service object or <code>ServiceFactory</code>.
2703         * @param dict A dictionary of properties that further describe the
2704         *             service or null.
2705         * @return A <code>ServiceRegistration</code> object or null.
2706        **/
2707        ServiceRegistration registerService(
2708            BundleImpl bundle, String[] classNames, Object svcObj, Dictionary dict)
2709        {
2710            if (classNames == null)
2711            {
2712                throw new NullPointerException("Service class names cannot be null.");
2713            }
2714            else if (svcObj == null)
2715            {
2716                throw new IllegalArgumentException("Service object cannot be null.");
2717            }
2718    
2719            // Acquire bundle lock.
2720            try
2721            {
2722                if (bundle.isExtension())
2723                {
2724    // TODO: EXTENSIONMANAGER - Verify this.
2725                    acquireBundleLock(bundle, Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE);
2726                }
2727                else
2728                {
2729                    acquireBundleLock(bundle, Bundle.STARTING | Bundle.ACTIVE);
2730                }
2731            }
2732            catch (IllegalStateException ex)
2733            {
2734                throw new IllegalStateException(
2735                    "Can only register services while bundle is active or activating.");
2736            }
2737    
2738            ServiceRegistration reg = null;
2739    
2740            try
2741            {
2742                // Check to make sure that the service object is
2743                // an instance of all service classes; ignore if
2744                // service object is a service factory.
2745                if (!(svcObj instanceof ServiceFactory))
2746                {
2747                    for (int i = 0; i < classNames.length; i++)
2748                    {
2749                        Class clazz = Util.loadClassUsingClass(svcObj.getClass(), classNames[i], m_secureAction);
2750                        if (clazz == null)
2751                        {
2752                            throw new IllegalArgumentException(
2753                                "Cannot cast service: " + classNames[i]);
2754                        }
2755                        else if (!clazz.isAssignableFrom(svcObj.getClass()))
2756                        {
2757                            throw new IllegalArgumentException(
2758                                "Service object is not an instance of \""
2759                                + classNames[i] + "\".");
2760                        }
2761                    }
2762                }
2763    
2764                reg = m_registry.registerService(bundle, classNames, svcObj, dict);
2765            }
2766            finally
2767            {
2768                // Always release bundle lock.
2769                releaseBundleLock(bundle);
2770            }
2771    
2772            // Check to see if this a listener hook; if so, then we need
2773            // to invoke the callback with all existing service listeners.
2774            if (ServiceRegistry.isHook(classNames, ListenerHook.class, svcObj))
2775            {
2776                m_registry.invokeHook(reg.getReference(), this, new InvokeHookCallback()
2777                {
2778                    public void invokeHook(Object hook)
2779                    {
2780                        ((ListenerHook) hook).
2781                            added(m_dispatcher.wrapAllServiceListeners(false));
2782                    }
2783                });
2784            }
2785    
2786            // TODO: CONCURRENCY - Reconsider firing event here, outside of the
2787            // bundle lock.
2788    
2789            // NOTE: The service registered event is fired from the service
2790            // registry to the framework, where it is then redistributed to
2791            // interested service event listeners.
2792    
2793            return reg;
2794        }
2795    
2796        /**
2797         * Retrieves an array of {@link ServiceReference} objects based on calling bundle,
2798         * service class name, and filter expression.  Optionally checks for isAssignable to
2799         * make sure that the service can be cast to the
2800         * @param bundle Calling Bundle
2801         * @param className Service Classname or <code>null</code> for all
2802         * @param expr Filter Criteria or <code>null</code>
2803         * @return Array of ServiceReference objects that meet the criteria
2804         * @throws InvalidSyntaxException
2805         */
2806        ServiceReference[] getServiceReferences(
2807            final BundleImpl bundle, final String className,
2808            final String expr, final boolean checkAssignable)
2809            throws InvalidSyntaxException
2810        {
2811            // Define filter if expression is not null.
2812            Filter filter = null;
2813            if (expr != null)
2814            {
2815                filter = FrameworkUtil.createFilter(expr);
2816            }
2817    
2818            // Ask the service registry for all matching service references.
2819            final List refList = m_registry.getServiceReferences(className, filter);
2820    
2821            // Filter on assignable references
2822            if (checkAssignable)
2823            {
2824                for (int refIdx = 0; (refList != null) && (refIdx < refList.size()); refIdx++)
2825                {
2826                    // Get the current service reference.
2827                    ServiceReference ref = (ServiceReference) refList.get(refIdx);
2828    
2829                    // Now check for castability.
2830                    if (!Util.isServiceAssignable(bundle, ref))
2831                    {
2832                        refList.remove(refIdx);
2833                        refIdx--;
2834                    }
2835                }
2836            }
2837    
2838            // activate findhooks
2839            List findHooks = m_registry.getFindHooks();
2840            InvokeHookCallback callback = new InvokeHookCallback()
2841            {
2842                public void invokeHook(Object hook)
2843                {
2844                    ((FindHook) hook).find(bundle._getBundleContext(),
2845                        className,
2846                        expr,
2847                        !checkAssignable,
2848                        new ShrinkableCollection(refList));
2849                }
2850            };
2851            for (int i = 0; i < findHooks.size(); i++)
2852            {
2853                m_registry.invokeHook((ServiceReference) findHooks.get(i), this, callback);
2854            }
2855    
2856            if (refList.size() > 0)
2857            {
2858                return (ServiceReference[]) refList.toArray(new ServiceReference[refList.size()]);
2859            }
2860    
2861            return null;
2862        }
2863    
2864        /**
2865         * Retrieves Array of {@link ServiceReference} objects based on calling bundle, service class name,
2866         * optional filter expression, and optionally filters further on the version.
2867         * If running under a {@link SecurityManager}, checks that the calling bundle has permissions to
2868         * see the service references and removes references that aren't.
2869         * @param bundle Calling Bundle
2870         * @param className Service Classname or <code>null</code> for all
2871         * @param expr Filter Criteria or <code>null</code>
2872         * @param checkAssignable <code>true</code> to check for isAssignable, <code>false</code> to return all versions
2873         * @return Array of ServiceReference objects that meet the criteria
2874         * @throws InvalidSyntaxException
2875         */
2876        ServiceReference[] getAllowedServiceReferences(
2877            BundleImpl bundle, String className, String expr, boolean checkAssignable)
2878            throws InvalidSyntaxException
2879        {
2880            ServiceReference[] refs = getServiceReferences(bundle, className, expr, checkAssignable);
2881    
2882            Object sm = System.getSecurityManager();
2883    
2884            if ((sm == null) || (refs == null))
2885            {
2886                return refs;
2887            }
2888    
2889            List result = new ArrayList();
2890    
2891            for (int i = 0; i < refs.length; i++)
2892            {
2893                try
2894                {
2895                    ((SecurityManager) sm).checkPermission(new ServicePermission(refs[i], ServicePermission.GET));
2896                    result.add(refs[i]);
2897                }
2898                catch (Exception ex)
2899                {
2900                    // Ignore, since we are just testing permission.
2901                }
2902            }
2903    
2904            if (result.isEmpty())
2905            {
2906                return null;
2907            }
2908    
2909            return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]);
2910    
2911        }
2912    
2913        Object getService(Bundle bundle, ServiceReference ref)
2914        {
2915            try
2916            {
2917                return m_registry.getService(bundle, ref);
2918            }
2919            catch (ServiceException ex)
2920            {
2921                fireFrameworkEvent(FrameworkEvent.ERROR, ref.getBundle(), ex);
2922            }
2923    
2924            return null;
2925        }
2926    
2927        boolean ungetService(Bundle bundle, ServiceReference ref)
2928        {
2929            return m_registry.ungetService(bundle, ref);
2930        }
2931    
2932        File getDataFile(BundleImpl bundle, String s)
2933        {
2934            try
2935            {
2936                if (bundle == this)
2937                {
2938                    return m_cache.getSystemBundleDataFile(s);
2939                }
2940    
2941                return bundle.getArchive().getDataFile(s);
2942            }
2943            catch (Exception ex)
2944            {
2945                m_logger.log(Logger.LOG_ERROR, ex.getMessage());
2946                return null;
2947            }
2948        }
2949    
2950        //
2951        // PackageAdmin related methods.
2952        //
2953    
2954        /**
2955         * This method returns the bundle associated with the specified class if
2956         * the class was loaded from a bundle from this framework instance. If the
2957         * class was not loaded from a bundle or was loaded by a bundle in another
2958         * framework instance, then <tt>null</tt> is returned.
2959         *
2960         * @param clazz the class for which to find its associated bundle.
2961         * @return the bundle associated with the specified class or <tt>null</tt>
2962         *         if the class was not loaded by a bundle or its associated
2963         *         bundle belongs to a different framework instance.
2964        **/
2965        Bundle getBundle(Class clazz)
2966        {
2967            if (clazz.getClassLoader() instanceof BundleReference)
2968            {
2969                // Only return the bundle if it is from this framework.
2970                BundleReference br = (BundleReference) clazz.getClassLoader();
2971                return ((br.getBundle() instanceof BundleImpl)
2972                    && (((BundleImpl) br.getBundle()).getFramework() == this))
2973                        ? br.getBundle() : null;
2974            }
2975            try
2976            {
2977                return (m_extensionManager.getModule().getClassByDelegation(clazz.getName()) == clazz)
2978                    ? this : null;
2979            }
2980            catch(ClassNotFoundException ex)
2981            {
2982                return null;
2983            }
2984        }
2985    
2986        /**
2987         * Returns the exported packages associated with the specified
2988         * package name. This is used by the PackageAdmin service
2989         * implementation.
2990         *
2991         * @param pkgName The name of the exported package to find.
2992         * @return The exported package or null if no matching package was found.
2993        **/
2994        ExportedPackage[] getExportedPackages(String pkgName)
2995        {
2996            // First, get all exporters of the package.
2997            List exports =
2998                m_resolverState.getResolvedCandidates(
2999                    new Requirement(
3000                        ICapability.PACKAGE_NAMESPACE,
3001                        null,
3002                        new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, pkgName, false) }), null);
3003    
3004            if (exports != null)
3005            {
3006                List pkgs = new ArrayList();
3007    
3008                Requirement req = new Requirement(ICapability.PACKAGE_NAMESPACE,
3009                    null,
3010                    new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, pkgName, false) });
3011    
3012                for (int pkgIdx = 0; pkgIdx < exports.size(); pkgIdx++)
3013                {
3014                    // Get the bundle associated with the current exporting module.
3015                    BundleImpl bundle = (BundleImpl)
3016                        ((ICapability) exports.get(pkgIdx)).getModule().getBundle();
3017    
3018                    // We need to find the version of the exported package, but this
3019                    // is tricky since there may be multiple versions of the package
3020                    // offered by a given bundle, since multiple revisions of the
3021                    // bundle JAR file may exist if the bundle was updated without
3022                    // refreshing the framework. In this case, each revision of the
3023                    // bundle JAR file is represented as a module in the BundleInfo
3024                    // module array, which is ordered from oldest to newest. We assume
3025                    // that the first module found to be exporting the package is the
3026                    // provider of the package, which makes sense since it must have
3027                    // been resolved first.
3028                    IModule[] modules = bundle.getModules();
3029                    for (int modIdx = 0; modIdx < modules.length; modIdx++)
3030                    {
3031                        ICapability[] ec = modules[modIdx].getCapabilities();
3032                        for (int i = 0; (ec != null) && (i < ec.length); i++)
3033                        {
3034                            if (ec[i].getNamespace().equals(req.getNamespace()) &&
3035                                req.isSatisfied(ec[i]))
3036                            {
3037                                pkgs.add(new ExportedPackageImpl(this, bundle, modules[modIdx], (Capability) ec[i]));
3038                            }
3039                        }
3040                    }
3041                }
3042    
3043                return (pkgs.isEmpty()) ? null : (ExportedPackage[]) pkgs.toArray(new ExportedPackage[pkgs.size()]);
3044            }
3045    
3046            return null;
3047        }
3048    
3049        /**
3050         * Returns an array of all actively exported packages from the specified
3051         * bundle or if the specified bundle is <tt>null</tt> an array
3052         * containing all actively exported packages by all bundles.
3053         *
3054         * @param b The bundle whose exported packages are to be retrieved
3055         *        or <tt>null</tt> if the exported packages of all bundles are
3056         *        to be retrieved.
3057         * @return An array of exported packages.
3058        **/
3059        ExportedPackage[] getExportedPackages(Bundle b)
3060        {
3061            List list = new ArrayList();
3062    
3063            // If a bundle is specified, then return its
3064            // exported packages.
3065            if (b != null)
3066            {
3067                BundleImpl bundle = (BundleImpl) b;
3068                getExportedPackages(bundle, list);
3069            }
3070            // Otherwise return all exported packages.
3071            else
3072            {
3073                // To create a list of all exported packages, we must look
3074                // in the installed and uninstalled sets of bundles. To
3075                // ensure a somewhat consistent view, we will gather all
3076                // of this information from within the installed bundle
3077                // lock.
3078                synchronized (m_installedBundleLock_Priority2)
3079                {
3080                    // First get exported packages from uninstalled bundles.
3081                    synchronized (m_uninstalledBundlesLock_Priority3)
3082                    {
3083                        for (int bundleIdx = 0;
3084                            (m_uninstalledBundles != null) && (bundleIdx < m_uninstalledBundles.length);
3085                            bundleIdx++)
3086                        {
3087                            BundleImpl bundle = m_uninstalledBundles[bundleIdx];
3088                            getExportedPackages(bundle, list);
3089                        }
3090                    }
3091    
3092                    // Now get exported packages from installed bundles.
3093                    Bundle[] bundles = getBundles();
3094                    for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
3095                    {
3096                        BundleImpl bundle = (BundleImpl) bundles[bundleIdx];
3097                        getExportedPackages(bundle, list);
3098                    }
3099                }
3100            }
3101    
3102            return (list.isEmpty())
3103                ? null
3104                : (ExportedPackage[]) list.toArray(new ExportedPackage[list.size()]);
3105        }
3106    
3107        /**
3108         * Adds any current active exported packages from the specified bundle
3109         * to the passed in list.
3110         * @param bundle The bundle from which to retrieve exported packages.
3111         * @param list The list to which the exported packages are added
3112        **/
3113        private void getExportedPackages(BundleImpl bundle, List list)
3114        {
3115            // Since a bundle may have many modules associated with it,
3116            // one for each revision in the cache, search each module
3117            // for each revision to get all exports.
3118            IModule[] modules = bundle.getModules();
3119            for (int modIdx = 0; modIdx < modules.length; modIdx++)
3120            {
3121                ICapability[] caps = modules[modIdx].getCapabilities();
3122                if ((caps != null) && (caps.length > 0))
3123                {
3124                    for (int capIdx = 0; capIdx < caps.length; capIdx++)
3125                    {
3126                        // See if the target bundle's module is one of the
3127                        // resolved exporters of the package.
3128                        if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
3129                        {
3130                            List resolvedCaps = m_resolverState.getResolvedCandidates(
3131                                new Requirement(
3132                                    ICapability.PACKAGE_NAMESPACE,
3133                                    null,
3134                                    new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, ((Capability) caps[capIdx]).getPackageName(), false) }), null);
3135    
3136                            // Search through the current providers to find the target module.
3137                            for (int i = 0; (resolvedCaps != null) && (i < resolvedCaps.size()); i++)
3138                            {
3139                                if ((ICapability) resolvedCaps.get(i) == caps[capIdx])
3140                                {
3141                                    list.add(new ExportedPackageImpl(
3142                                        this, bundle, modules[modIdx], (Capability) caps[capIdx]));
3143                                }
3144                            }
3145                        }
3146                    }
3147                }
3148            }
3149        }
3150    
3151        Bundle[] getDependentBundles(BundleImpl exporter)
3152        {
3153            // Create list for storing importing bundles.
3154            List list = new ArrayList();
3155    
3156            // Get all dependent modules from all exporter module revisions.
3157            IModule[] modules = exporter.getModules();
3158            for (int modIdx = 0; modIdx < modules.length; modIdx++)
3159            {
3160                IModule[] dependents = ((ModuleImpl) modules[modIdx]).getDependents();
3161                for (int depIdx = 0;
3162                    (dependents != null) && (depIdx < dependents.length);
3163                    depIdx++)
3164                {
3165                    list.add(dependents[depIdx].getBundle());
3166                }
3167            }
3168    
3169            // Return the results.
3170            if (list.size() > 0)
3171            {
3172                return (Bundle[]) list.toArray(new Bundle[list.size()]);
3173            }
3174    
3175            return null;
3176        }
3177    
3178        Bundle[] getImportingBundles(ExportedPackage ep)
3179        {
3180            // Create list for storing importing bundles.
3181            List list = new ArrayList();
3182    
3183            // Get exporting bundle information.
3184            BundleImpl exporter = (BundleImpl) ep.getExportingBundle();
3185    
3186            // Get all importers and requirers for all revisions of the bundle.
3187            // The spec says that require-bundle should be returned with importers.
3188            IModule[] expModules = exporter.getModules();
3189            for (int expIdx = 0; (expModules != null) && (expIdx < expModules.length); expIdx++)
3190            {
3191                // Include any importers that have wires to the specific
3192                // exported package.
3193                IModule[] dependents = ((ModuleImpl) expModules[expIdx]).getDependentImporters();
3194                for (int depIdx = 0; (dependents != null) && (depIdx < dependents.length); depIdx++)
3195                {
3196                    IWire[] wires = dependents[depIdx].getWires();
3197                    for (int wireIdx = 0; (wires != null) && (wireIdx < wires.length); wireIdx++)
3198                    {
3199                        if ((wires[wireIdx].getExporter() == expModules[expIdx])
3200                            && (wires[wireIdx].hasPackage(ep.getName())))
3201                        {
3202                            list.add(dependents[depIdx].getBundle());
3203                        }
3204                    }
3205                }
3206                dependents = ((ModuleImpl) expModules[expIdx]).getDependentRequirers();
3207                for (int depIdx = 0; (dependents != null) && (depIdx < dependents.length); depIdx++)
3208                {
3209                    list.add(dependents[depIdx].getBundle());
3210                }
3211            }
3212    
3213            // Return the results.
3214            return (Bundle[]) list.toArray(new Bundle[list.size()]);
3215        }
3216    
3217        boolean resolveBundles(Bundle[] targets)
3218        {
3219            // Acquire global lock.
3220            boolean locked = acquireGlobalLock();
3221            if (!locked)
3222            {
3223                m_logger.log(
3224                    Logger.LOG_WARNING,
3225                    "Unable to acquire global lock to perform resolve.",
3226                    null);
3227                return false;
3228            }
3229    
3230            try
3231            {
3232                // Determine set of bundles to be resolved, which is either the
3233                // specified bundles or all bundles if null.
3234                if (targets == null)
3235                {
3236                    List list = new ArrayList();
3237    
3238                    // Add all unresolved bundles to the list.
3239                    synchronized (m_installedBundleLock_Priority2)
3240                    {
3241                        Iterator iter = m_installedBundleMap.values().iterator();
3242                        while (iter.hasNext())
3243                        {
3244                            BundleImpl bundle = (BundleImpl) iter.next();
3245                            if (bundle.getState() == Bundle.INSTALLED)
3246                            {
3247                                list.add(bundle);
3248                            }
3249                        }
3250                    }
3251    
3252                    // Create an array.
3253                    if (list.size() > 0)
3254                    {
3255                        targets = (Bundle[]) list.toArray(new BundleImpl[list.size()]);
3256                    }
3257                }
3258    
3259                // Now resolve each target bundle.
3260                boolean result = true;
3261    
3262                // If there are targets, then resolve each one.
3263                for (int i = 0; (targets != null) && (i < targets.length); i++)
3264                {
3265                    try
3266                    {
3267                        resolveBundle((BundleImpl) targets[i]);
3268                    }
3269                    catch (BundleException ex)
3270                    {
3271                        result = false;
3272                        m_logger.log(
3273                            Logger.LOG_WARNING,
3274                            "Unable to resolve bundle " + targets[i].getBundleId(),
3275                            ex);
3276                    }
3277                }
3278    
3279                return result;
3280            }
3281            finally
3282            {
3283                // Always release the global lock.
3284                releaseGlobalLock();
3285            }
3286        }
3287    
3288        private void resolveBundle(BundleImpl bundle) throws BundleException
3289        {
3290            try
3291            {
3292                m_felixResolver.resolve(bundle.getCurrentModule());
3293            }
3294            catch (ResolveException ex)
3295            {
3296                if (ex.getModule() != null)
3297                {
3298                    Bundle b = ((ModuleImpl) ex.getModule()).getBundle();
3299                    throw new BundleException(
3300                        "Unresolved constraint in bundle " + b + ": "
3301                        + ((ex.getRequirement() == null)
3302                            ? ex.getMessage() : ex.getRequirement().toString()));
3303                }
3304                else
3305                {
3306                    throw new BundleException(ex.getMessage());
3307                }
3308            }
3309        }
3310    
3311        void refreshPackages(Bundle[] targets)
3312        {
3313            // Acquire global lock.
3314            boolean locked = acquireGlobalLock();
3315            if (!locked)
3316            {
3317                // If the thread calling holds bundle locks, then we might not
3318                // be able to get the global lock. However, in practice this
3319                // should not happen since the calls to this method have either
3320                // already acquired the global lock or it is PackageAdmin which
3321                // doesn't hold bundle locks.
3322                throw new IllegalStateException(
3323                    "Unable to acquire global lock for refresh.");
3324            }
3325    
3326            // Determine set of bundles to refresh, which is all transitive
3327            // dependencies of specified set or all transitive dependencies
3328            // of all bundles if null is specified.
3329            Bundle[] newTargets = targets;
3330            if (newTargets == null)
3331            {
3332                List list = new ArrayList();
3333    
3334                // First add all uninstalled bundles.
3335                synchronized (m_uninstalledBundlesLock_Priority3)
3336                {
3337                    for (int i = 0;
3338                        (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
3339                        i++)
3340                    {
3341                        list.add(m_uninstalledBundles[i]);
3342                    }
3343                }
3344    
3345                // Then add all updated bundles.
3346                synchronized (m_installedBundleLock_Priority2)
3347                {
3348                    Iterator iter = m_installedBundleMap.values().iterator();
3349                    while (iter.hasNext())
3350                    {
3351                        BundleImpl bundle = (BundleImpl) iter.next();
3352                        if (bundle.isRemovalPending())
3353                        {
3354                            list.add(bundle);
3355                        }
3356                    }
3357                }
3358    
3359                // Create an array.
3360                if (list.size() > 0)
3361                {
3362                    newTargets = (Bundle[]) list.toArray(new Bundle[list.size()]);
3363                }
3364            }
3365    
3366            // If there are targets, then find all dependencies for each one.
3367            BundleImpl[] bundles = null;
3368            if (newTargets != null)
3369            {
3370                // Create map of bundles that import the packages
3371                // from the target bundles.
3372                Map map = new HashMap();
3373                for (int targetIdx = 0; targetIdx < newTargets.length; targetIdx++)
3374                {
3375                    // Add the current target bundle to the map of
3376                    // bundles to be refreshed.
3377                    BundleImpl target = (BundleImpl) newTargets[targetIdx];
3378                    map.put(target, target);
3379                    // Add all importing bundles to map.
3380                    populateDependentGraph(target, map);
3381                }
3382    
3383                bundles = (BundleImpl[]) map.values().toArray(new BundleImpl[map.size()]);
3384            }
3385    
3386            // Now refresh each bundle.
3387            try
3388            {
3389                boolean restart = false;
3390    
3391                Bundle systemBundle = this;
3392    
3393                // We need to restart the framework if either an extension bundle is
3394                // refreshed or the system bundle is refreshed and any extension bundle
3395                // has been updated or uninstalled.
3396                for (int i = 0; (bundles != null) && !restart && (i < bundles.length); i++)
3397                {
3398                    if (systemBundle == bundles[i])
3399                    {
3400                        Bundle[] allBundles = getBundles();
3401                        for (int j = 0; !restart && j < allBundles.length; j++)
3402                        {
3403                            if (((BundleImpl) allBundles[j]).isExtension() &&
3404                                (allBundles[j].getState() == Bundle.INSTALLED))
3405                            {
3406                                restart = true;
3407                            }
3408                        }
3409                    }
3410                }
3411    
3412                // Remove any targeted bundles from the uninstalled bundles
3413                // array, since they will be removed from the system after
3414                // the refresh.
3415                // TODO: FRAMEWORK - Is this correct?
3416                for (int i = 0; (bundles != null) && (i < bundles.length); i++)
3417                {
3418                    forgetUninstalledBundle(bundles[i]);
3419                }
3420                // If there are targets, then refresh each one.
3421                if (bundles != null)
3422                {
3423                    // At this point the map contains every bundle that has been
3424                    // updated and/or removed as well as all bundles that import
3425                    // packages from these bundles.
3426    
3427                    // Create refresh helpers for each bundle.
3428                    RefreshHelper[] helpers = new RefreshHelper[bundles.length];
3429                    for (int i = 0; i < bundles.length; i++)
3430                    {
3431                        helpers[i] = new RefreshHelper(bundles[i]);
3432                    }
3433    
3434                    // Stop, purge or remove, and reinitialize all bundles first.
3435                    // TODO: FRAMEWORK - this will stop the system bundle if
3436                    // somebody called refresh 0. Is this what we want?
3437                    for (int i = 0; i < helpers.length; i++)
3438                    {
3439                        if (helpers[i] != null)
3440                        {
3441                            helpers[i].stop();
3442                            helpers[i].refreshOrRemove();
3443                        }
3444                    }
3445    
3446                    // Then restart all bundles that were previously running.
3447                    for (int i = 0; i < helpers.length; i++)
3448                    {
3449                        if (helpers[i] != null)
3450                        {
3451                            helpers[i].restart();
3452                        }
3453                    }
3454                }
3455    
3456                if (restart)
3457                {
3458                    try
3459                    {
3460                        update();
3461                    }
3462                    catch (BundleException ex)
3463                    {
3464                        m_logger.log(Logger.LOG_ERROR, "Framework restart error.", ex);
3465                    }
3466                }
3467            }
3468            finally
3469            {
3470                // Always release the global lock.
3471                releaseGlobalLock();
3472            }
3473    
3474            fireFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, this, null);
3475        }
3476    
3477        private void populateDependentGraph(BundleImpl exporter, Map map)
3478        {
3479            // Get all dependent bundles of this bundle.
3480            Bundle[] dependents = getDependentBundles(exporter);
3481    
3482            for (int depIdx = 0;
3483                (dependents != null) && (depIdx < dependents.length);
3484                depIdx++)
3485            {
3486                // Avoid cycles if the bundle is already in map.
3487                if (!map.containsKey(dependents[depIdx]))
3488                {
3489                    // Add each importing bundle to map.
3490                    map.put(dependents[depIdx], dependents[depIdx]);
3491                    // Now recurse into each bundle to get its importers.
3492                    populateDependentGraph(
3493                        (BundleImpl) dependents[depIdx], map);
3494                }
3495            }
3496        }
3497    
3498        //
3499        // Miscellaneous private methods.
3500        //
3501    
3502        private volatile SecurityProvider m_securityProvider;
3503    
3504        SecurityProvider getSecurityProvider()
3505        {
3506            return m_securityProvider;
3507        }
3508    
3509        void setSecurityProvider(SecurityProvider securityProvider)
3510        {
3511            m_securityProvider = securityProvider;
3512        }
3513    
3514        Object getSignerMatcher(BundleImpl bundle, int signersType)
3515        {
3516            if ((bundle != this) && (m_securityProvider != null))
3517            {
3518                return m_securityProvider.getSignerMatcher(bundle, signersType);
3519            }
3520            return new HashMap();
3521        }
3522    
3523        boolean impliesBundlePermission(BundleProtectionDomain bundleProtectionDomain, Permission permission, boolean direct)
3524        {
3525            if (m_securityProvider != null)
3526            {
3527                return m_securityProvider.hasBundlePermission(bundleProtectionDomain, permission, direct);
3528            }
3529            return true;
3530        }
3531    
3532        private BundleActivator createBundleActivator(BundleImpl impl)
3533            throws Exception
3534        {
3535            // CONCURRENCY NOTE:
3536            // This method is called indirectly from startBundle() (via _startBundle()),
3537            // which has the bundle lock, so there is no need to do any locking here.
3538    
3539            // Get the activator class from the header map.
3540            BundleActivator activator = null;
3541            Map headerMap = impl.getCurrentModule().getHeaders();
3542            String className = (String) headerMap.get(Constants.BUNDLE_ACTIVATOR);
3543            // Try to instantiate activator class if present.
3544            if (className != null)
3545            {
3546                className = className.trim();
3547                Class clazz;
3548                try
3549                {
3550                    clazz = impl.getCurrentModule().getClassByDelegation(className);
3551                }
3552                catch (ClassNotFoundException ex)
3553                {
3554                    throw new BundleException("Not found: " + className, ex);
3555                }
3556                activator = (BundleActivator) clazz.newInstance();
3557            }
3558    
3559            return activator;
3560        }
3561    
3562        private void refreshBundle(BundleImpl bundle) throws Exception
3563        {
3564            // Acquire bundle lock.
3565            try
3566            {
3567                acquireBundleLock(bundle, Bundle.INSTALLED | Bundle.RESOLVED);
3568            }
3569            catch (IllegalStateException ex)
3570            {
3571                throw new BundleException(
3572                    "Bundle state has changed unexpectedly during refresh.");
3573            }
3574    
3575            try
3576            {
3577                // Reset the bundle object and fire UNRESOLVED event.
3578                ((BundleImpl) bundle).refresh();
3579            }
3580            catch (Exception ex)
3581            {
3582                fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
3583            }
3584            finally
3585            {
3586                // Always release the bundle lock.
3587                releaseBundleLock(bundle);
3588            }
3589        }
3590    
3591        //
3592        // Event-related methods.
3593        //
3594    
3595        /**
3596         * Fires bundle events.
3597        **/
3598        private void fireFrameworkEvent(
3599            int type, Bundle bundle, Throwable throwable)
3600        {
3601            m_dispatcher.fireFrameworkEvent(new FrameworkEvent(type, bundle, throwable));
3602        }
3603    
3604        /**
3605         * Fires bundle events.
3606         *
3607         * @param type The type of bundle event to fire.
3608         * @param bundle The bundle associated with the event.
3609        **/
3610        private void fireBundleEvent(int type, Bundle bundle)
3611        {
3612            m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle));
3613        }
3614    
3615        /**
3616         * Fires service events.
3617         *
3618         * @param event The service event to fire.
3619         * @param reg The service registration associated with the service object.
3620        **/
3621        private void fireServiceEvent(ServiceEvent event, Dictionary oldProps)
3622        {
3623            m_dispatcher.fireServiceEvent(event, oldProps, this);
3624        }
3625    
3626        //
3627        // Property related methods.
3628        //
3629    
3630        private void initializeFrameworkProperties()
3631        {
3632            // Standard OSGi properties.
3633            m_configMutableMap.put(
3634                FelixConstants.FRAMEWORK_VERSION,
3635                FelixConstants.FRAMEWORK_VERSION_VALUE);
3636            m_configMutableMap.put(
3637                FelixConstants.FRAMEWORK_VENDOR,
3638                FelixConstants.FRAMEWORK_VENDOR_VALUE);
3639            m_configMutableMap.put(
3640                FelixConstants.FRAMEWORK_LANGUAGE,
3641                System.getProperty("user.language"));
3642            m_configMutableMap.put(
3643                FelixConstants.FRAMEWORK_OS_VERSION,
3644                System.getProperty("os.version"));
3645            m_configMutableMap.put(
3646                FelixConstants.SUPPORTS_FRAMEWORK_EXTENSION,
3647                "true");
3648            m_configMutableMap.put(
3649                FelixConstants.SUPPORTS_FRAMEWORK_FRAGMENT,
3650                "true");
3651            m_configMutableMap.put(
3652                FelixConstants.SUPPORTS_FRAMEWORK_REQUIREBUNDLE,
3653                "true");
3654            m_configMutableMap.put(
3655                FelixConstants.SUPPORTS_BOOTCLASSPATH_EXTENSION,
3656                "false");
3657    
3658            String s = null;
3659            s = R4LibraryClause.normalizeOSName(System.getProperty("os.name"));
3660            m_configMutableMap.put(FelixConstants.FRAMEWORK_OS_NAME, s);
3661            s = R4LibraryClause.normalizeProcessor(System.getProperty("os.arch"));
3662            m_configMutableMap.put(FelixConstants.FRAMEWORK_PROCESSOR, s);
3663            m_configMutableMap.put(
3664                FelixConstants.FELIX_VERSION_PROPERTY, getFrameworkVersion());
3665        }
3666    
3667        /**
3668         * Read the framework version from the property file.
3669         * @return the framework version as a string.
3670        **/
3671        private static String getFrameworkVersion()
3672        {
3673            // The framework version property.
3674            Properties props = new Properties();
3675            InputStream in = Felix.class.getResourceAsStream("Felix.properties");
3676            if (in != null)
3677            {
3678                try
3679                {
3680                    props.load(in);
3681                }
3682                catch (IOException ex)
3683                {
3684                    ex.printStackTrace();
3685                }
3686            }
3687    
3688            // Maven uses a '-' to separate the version qualifier,
3689            // while OSGi uses a '.', so we need to convert to a '.'
3690            StringBuffer sb =
3691                new StringBuffer(
3692                    props.getProperty(
3693                        FelixConstants.FELIX_VERSION_PROPERTY, "0.0.0"));
3694            if (sb.toString().indexOf("-") >= 0)
3695            {
3696                sb.setCharAt(sb.toString().indexOf("-"), '.');
3697            }
3698            String toRet = sb.toString();
3699            if (toRet.contains("${pom"))
3700            {
3701                return "0.0.0";
3702            }
3703            else
3704            {
3705                return toRet;
3706            }
3707        }
3708    
3709        //
3710        // Private utility methods.
3711        //
3712    
3713        /**
3714         * Generated the next valid bundle identifier.
3715        **/
3716        private long loadNextId()
3717        {
3718            synchronized (m_nextIdLock)
3719            {
3720                // Read persisted next bundle identifier.
3721                InputStream is = null;
3722                BufferedReader br = null;
3723                try
3724                {
3725                    File file = m_cache.getSystemBundleDataFile("bundle.id");
3726                    is = m_secureAction.getFileInputStream(file);
3727                    br = new BufferedReader(new InputStreamReader(is));
3728                    return Long.parseLong(br.readLine());
3729                }
3730                catch (FileNotFoundException ex)
3731                {
3732                    // Ignore this case because we assume that this is the
3733                    // initial startup of the framework and therefore the
3734                    // file does not exist yet.
3735                }
3736                catch (Exception ex)
3737                {
3738                    m_logger.log(
3739                        Logger.LOG_WARNING,
3740                        "Unable to initialize next bundle identifier from persistent storage.",
3741                        ex);
3742                }
3743                finally
3744                {
3745                    try
3746                    {
3747                        if (br != null) br.close();
3748                        if (is != null) is.close();
3749                    }
3750                    catch (Exception ex)
3751                    {
3752                        m_logger.log(
3753                            Logger.LOG_WARNING,
3754                            "Unable to close next bundle identifier file.",
3755                            ex);
3756                    }
3757                }
3758            }
3759    
3760            return -1;
3761        }
3762    
3763        private long getNextId()
3764        {
3765            synchronized (m_nextIdLock)
3766            {
3767                // Save the current id.
3768                long id = m_nextId;
3769    
3770                // Increment the next id.
3771                m_nextId++;
3772    
3773                // Write the bundle state.
3774                OutputStream os = null;
3775                BufferedWriter bw = null;
3776                try
3777                {
3778                    File file = m_cache.getSystemBundleDataFile("bundle.id");
3779                    os = m_secureAction.getFileOutputStream(file);
3780                    bw = new BufferedWriter(new OutputStreamWriter(os));
3781                    String s = Long.toString(m_nextId);
3782                    bw.write(s, 0, s.length());
3783                }
3784                catch (Exception ex)
3785                {
3786                    m_logger.log(
3787                        Logger.LOG_WARNING,
3788                        "Unable to save next bundle identifier to persistent storage.",
3789                        ex);
3790                }
3791                finally
3792                {
3793                    try
3794                    {
3795                        if (bw != null) bw.close();
3796                        if (os != null) os.close();
3797                    }
3798                    catch (Exception ex)
3799                    {
3800                        m_logger.log(
3801                            Logger.LOG_WARNING,
3802                            "Unable to close next bundle identifier file.",
3803                            ex);
3804                    }
3805                }
3806    
3807                return id;
3808            }
3809        }
3810    
3811        //
3812        // Miscellaneous inner classes.
3813        //
3814    
3815        public class FelixResolver
3816        {
3817            private final Resolver m_resolver;
3818            private final FelixResolverState m_resolverState;
3819    
3820            public FelixResolver(Resolver resolver, FelixResolverState resolverState)
3821            {
3822                m_resolver = resolver;
3823                m_resolverState = resolverState;
3824            }
3825    
3826            public void resolve(IModule rootModule) throws ResolveException
3827            {
3828                // Although there is a race condition to check the bundle state
3829                // then lock it, we do this because we don't want to acquire the
3830                // a lock just to check if the module is resolved, which itself
3831                // is a safe read. If the module isn't resolved, we end up double
3832                // check the resolved status later.
3833                if (!rootModule.isResolved())
3834                {
3835                    // Acquire global lock.
3836                    boolean locked = acquireGlobalLock();
3837                    if (!locked)
3838                    {
3839                        throw new ResolveException(
3840                            "Unable to acquire global lock for resolve.", rootModule, null);
3841                    }
3842    
3843                    try
3844                    {
3845                        BundleImpl bundle = (BundleImpl) rootModule.getBundle();
3846    
3847                        // Extensions are resolved differently.
3848                        if (bundle.isExtension())
3849                        {
3850                            return;
3851                        }
3852    
3853                        // If the root module to resolve is a fragment, then we
3854                        // must find a host to attach it to and resolve the host
3855                        // instead, since the underlying resolver doesn't know
3856                        // how to deal with fragments.
3857                        IModule newRootModule = m_resolverState.findHost(rootModule);
3858                        if (!Util.isFragment(newRootModule))
3859                        {
3860                            // Resolve the module.
3861                            Map resolvedModuleWireMap = m_resolver.resolve(m_resolverState, newRootModule);
3862    
3863                            // Mark all modules as resolved.
3864                            markResolvedModules(resolvedModuleWireMap);
3865                        }
3866                    }
3867                    finally
3868                    {
3869                        // Always release the global lock.
3870                        releaseGlobalLock();
3871                    }
3872                }
3873            }
3874    
3875            public IWire resolveDynamicImport(IModule importer, String pkgName) throws ResolveException
3876            {
3877                IWire candidateWire = null;
3878    
3879                // We cannot dynamically import if the module is already resolved or
3880                // if it is not allowed, so check that first. Note: We check if the
3881                // dynamic import is allowed without holding any locks, but this is
3882                // okay since the resolver will double check later after we have
3883                // acquired the global lock below.
3884                if (importer.isResolved()
3885                    && (Resolver.findAllowedDynamicImport(importer, pkgName) != null))
3886                {
3887                    // Acquire global lock.
3888                    boolean locked = acquireGlobalLock();
3889                    if (!locked)
3890                    {
3891                        throw new ResolveException(
3892                            "Unable to acquire global lock for resolve.", importer, null);
3893                    }
3894    
3895                    try
3896                    {
3897                        // Double check to make sure that someone hasn't beaten us to
3898                        // dynamically importing the package, which can happen if two
3899                        // threads are racing to do so. If we have an existing wire,
3900                        // then just return it instead.
3901                        IWire[] wires = importer.getWires();
3902                        for (int i = 0; (wires != null) && (i < wires.length); i++)
3903                        {
3904                            if (wires[i].hasPackage(pkgName))
3905                            {
3906                                return wires[i];
3907                            }
3908                        }
3909    
3910                        Object[] result = m_resolver.resolveDynamicImport(m_resolverState, importer, pkgName);
3911                        if (result != null)
3912                        {
3913                            candidateWire = (IWire) result[0];
3914                            Map resolvedModuleWireMap = (Map) result[1];
3915    
3916                            // Mark all modules as resolved.
3917                            markResolvedModules(resolvedModuleWireMap);
3918    
3919                            // Dynamically add new wire to importing module.
3920                            if (candidateWire != null)
3921                            {
3922                                wires = importer.getWires();
3923                                IWire[] newWires = null;
3924                                if (wires == null)
3925                                {
3926                                    newWires = new IWire[1];
3927                                }
3928                                else
3929                                {
3930                                    newWires = new IWire[wires.length + 1];
3931                                    System.arraycopy(wires, 0, newWires, 0, wires.length);
3932                                }
3933    
3934                                newWires[newWires.length - 1] = candidateWire;
3935                                ((ModuleImpl) importer).setWires(newWires);
3936    m_logger.log(Logger.LOG_DEBUG, "DYNAMIC WIRE: " + newWires[newWires.length - 1]);
3937                            }
3938                        }
3939                    }
3940                    finally
3941                    {
3942                        // Always release the global lock.
3943                        releaseGlobalLock();
3944                    }
3945                }
3946    
3947                return candidateWire;
3948            }
3949    
3950            public synchronized List getResolvedCandidates(IRequirement req, IModule reqModule)
3951            {
3952                return m_resolverState.getResolvedCandidates(req, reqModule);
3953            }
3954    
3955            public synchronized List getUnresolvedCandidates(IRequirement req, IModule reqModule)
3956            {
3957                return m_resolverState.getUnresolvedCandidates(req, reqModule);
3958            }
3959    
3960            private void markResolvedModules(Map resolvedModuleWireMap)
3961            {
3962                if (resolvedModuleWireMap != null)
3963                {
3964                    Iterator iter = resolvedModuleWireMap.entrySet().iterator();
3965                    // Iterate over the map to mark the modules as resolved and
3966                    // update our resolver data structures.
3967                    List wireList = new ArrayList();
3968                    while (iter.hasNext())
3969                    {
3970                        wireList.clear();
3971    
3972                        Map.Entry entry = (Map.Entry) iter.next();
3973                        IModule module = (IModule) entry.getKey();
3974                        IWire[] wires = (IWire[]) entry.getValue();
3975    
3976                        // Only add wires attribute if some exist; export
3977                        // only modules may not have wires.
3978    // TODO: RESOLVER - Seems stupid that we package these up as wires to tear them apart.
3979                        if (wires.length > 0)
3980                        {
3981                            for (int wireIdx = 0; wireIdx < wires.length; wireIdx++)
3982                            {
3983                                wireList.add(wires[wireIdx]);
3984                                m_logger.log(
3985                                    Logger.LOG_DEBUG,
3986                                    "WIRE: " + wires[wireIdx]);
3987                            }
3988                            wires = (IWire[]) wireList.toArray(new IWire[wireList.size()]);
3989                            ((ModuleImpl) module).setWires(wires);
3990                        }
3991    
3992                        // Resolve all attached fragments.
3993                        IModule[] fragments = ((ModuleImpl) module).getFragments();
3994                        for (int i = 0; (fragments != null) && (i < fragments.length); i++)
3995                        {
3996                            ((ModuleImpl) fragments[i]).setResolved();
3997                            // Update the state of the module's bundle to resolved as well.
3998                            markBundleResolved(fragments[i]);
3999                            m_logger.log(
4000                                Logger.LOG_DEBUG,
4001                                "FRAGMENT WIRE: " + fragments[i] + " -> hosted by -> " + module);
4002                        }
4003                        // Update the resolver state to show the module as resolved.
4004                        ((ModuleImpl) module).setResolved();
4005                        m_resolverState.moduleResolved(module);
4006                        // Update the state of the module's bundle to resolved as well.
4007                        markBundleResolved(module);
4008                    }
4009                }
4010            }
4011    
4012            private void markBundleResolved(IModule module)
4013            {
4014                // Update the bundle's state to resolved when the
4015                // current module is resolved; just ignore resolve
4016                // events for older revisions since this only occurs
4017                // when an update is done on an unresolved bundle
4018                // and there was no refresh performed.
4019                BundleImpl bundle = (BundleImpl) module.getBundle();
4020    
4021                // Lock the bundle first.
4022                try
4023                {
4024    // TODO: RESOLVER - Seems like we should release the lock before we fire the event.
4025                    // Acquire bundle lock.
4026                    try
4027                    {
4028                        acquireBundleLock(bundle, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE);
4029                    }
4030                    catch (IllegalStateException ex)
4031                    {
4032                        // There is nothing we can do.
4033                    }
4034                    if (bundle.getCurrentModule() == module)
4035                    {
4036                        if (bundle.getState() != Bundle.INSTALLED)
4037                        {
4038                            m_logger.log(
4039                                Logger.LOG_WARNING,
4040                                "Received a resolve event for a bundle that has already been resolved.");
4041                        }
4042                        else
4043                        {
4044                            setBundleStateAndNotify(bundle, Bundle.RESOLVED);
4045                            fireBundleEvent(BundleEvent.RESOLVED, bundle);
4046                        }
4047                    }
4048                }
4049                finally
4050                {
4051                    releaseBundleLock(bundle);
4052                }
4053            }
4054        }
4055    
4056        class SystemBundleActivator implements BundleActivator, Runnable
4057        {
4058            public void start(BundleContext context) throws Exception
4059            {
4060                // Add the bundle activator for the package admin service.
4061                m_activatorList.add(0, new PackageAdminActivator(Felix.this));
4062                // Add the bundle activator for the start level service.
4063                m_activatorList.add(0, new StartLevelActivator(m_logger, Felix.this));
4064                // Add the bundle activator for the url handler service.
4065                m_activatorList.add(0, new URLHandlersActivator(m_configMap, Felix.this));
4066    
4067                // Start all activators.
4068                for (int i = 0; i < m_activatorList.size(); i++)
4069                {
4070                    Felix.m_secureAction.startActivator(
4071                        (BundleActivator) m_activatorList.get(i), context);
4072                }
4073            }
4074    
4075            public void stop(BundleContext context)
4076            {
4077                // Spec says stop() on SystemBundle should return immediately and
4078                // shutdown framework on another thread.
4079                if (m_shutdownThread == null)
4080                {
4081                    // Initial call of stop, so kick off shutdown.
4082                    m_shutdownThread = new Thread(this, "FelixShutdown");
4083                    m_shutdownThread.start();
4084                }
4085            }
4086    
4087            public void run()
4088            {
4089                // The state of the framework should be STOPPING, so
4090                // acquire the bundle lock to verify it.
4091                acquireBundleLock(Felix.this, Bundle.STOPPING);
4092                releaseBundleLock(Felix.this);
4093    
4094                // Use the start level service to set the start level to zero
4095                // in order to stop all bundles in the framework. Since framework
4096                // shutdown happens on its own thread, we can wait for the start
4097                // level service to finish before proceeding by calling the
4098                // non-spec setStartLevelAndWait() method.
4099                try
4100                {
4101                    StartLevelImpl sl = (StartLevelImpl) getService(
4102                        Felix.this,
4103                        getServiceReferences(Felix.this, StartLevel.class.getName(), null, true)[0]);
4104                    sl.setStartLevelAndWait(0);
4105                }
4106                catch (InvalidSyntaxException ex)
4107                {
4108                    // Should never happen.
4109                }
4110    
4111                // Shutdown event dispatching queue.
4112                EventDispatcher.shutdown();
4113    
4114                // Since there may be updated and uninstalled bundles that
4115                // have not been refreshed, we will take care of refreshing
4116                // them during shutdown.
4117    
4118                // Refresh all updated bundles.
4119                Bundle[] bundles = getBundles();
4120                for (int i = 0; i < bundles.length; i++)
4121                {
4122                    BundleImpl bundle = (BundleImpl) bundles[i];
4123                    if (bundle.isRemovalPending())
4124                    {
4125                        try
4126                        {
4127                            refreshBundle(bundle);
4128                        }
4129                        catch (Exception ex)
4130                        {
4131                            fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
4132                            m_logger.log(Logger.LOG_ERROR, "Unable to purge bundle "
4133                                + bundle._getLocation(), ex);
4134                        }
4135                    }
4136                }
4137    
4138                // Delete uninstalled bundles.
4139                for (int i = 0;
4140                    (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
4141                    i++)
4142                {
4143                    try
4144                    {
4145                        m_uninstalledBundles[i].closeAndDelete();
4146                    }
4147                    catch (Exception ex)
4148                    {
4149                        m_logger.log(
4150                            Logger.LOG_ERROR,
4151                            "Unable to remove "
4152                            + m_uninstalledBundles[i]._getLocation(), ex);
4153                    }
4154                }
4155    
4156                // Dispose of the bundles to close their associated contents.
4157                bundles = getBundles();
4158                for (int i = 0; i < bundles.length; i++)
4159                {
4160                    ((BundleImpl) bundles[i]).close();
4161                }
4162    
4163                // Stop all system bundle activators.
4164                for (int i = 0; i < m_activatorList.size(); i++)
4165                {
4166                    try
4167                    {
4168                        Felix.m_secureAction.stopActivator((BundleActivator)
4169                            m_activatorList.get(i), _getBundleContext());
4170                    }
4171                    catch (Throwable throwable)
4172                    {
4173                        m_logger.log(
4174                            Logger.LOG_WARNING,
4175                            "Exception stopping a system bundle activator.",
4176                            throwable);
4177                    }
4178                }
4179    
4180                if (m_securityManager != null)
4181                {
4182                    System.setSecurityManager(null);
4183                    m_securityManager = null;
4184                }
4185    
4186                if (m_extensionManager != null)
4187                {
4188                    m_extensionManager.removeExtensions(Felix.this);
4189                }
4190    
4191                // Set the framework state to resolved.
4192                acquireBundleLock(Felix.this, Bundle.STOPPING);
4193                try
4194                {
4195                    // Clean up the bundle context.
4196                    ((BundleContextImpl) _getBundleContext()).invalidate();
4197                    setBundleContext(null);
4198    
4199                    // Set the framework state to resolved and open
4200                    // the shutdown gate.
4201                    setBundleStateAndNotify(Felix.this, Bundle.RESOLVED);
4202                    m_shutdownGate.open();
4203                    m_shutdownGate = null;
4204                    m_shutdownThread = null;
4205                }
4206                finally
4207                {
4208                    releaseBundleLock(Felix.this);
4209                }
4210            }
4211        }
4212    
4213        /**
4214         * Simple class that is used in <tt>refreshPackages()</tt> to embody
4215         * the refresh logic in order to keep the code clean. This class is
4216         * not static because it needs access to framework event firing methods.
4217        **/
4218        private class RefreshHelper
4219        {
4220            private BundleImpl m_bundle = null;
4221            private int m_oldState = Bundle.INSTALLED;
4222    
4223            public RefreshHelper(Bundle bundle)
4224            {
4225                m_bundle = (BundleImpl) bundle;
4226            }
4227    
4228            public void stop()
4229            {
4230    // TODO: LOCKING - This is not really correct.
4231                if (m_bundle.getState() == Bundle.ACTIVE)
4232                {
4233                    m_oldState = Bundle.ACTIVE;
4234                    try
4235                    {
4236                        stopBundle(m_bundle, false);
4237                    }
4238                    catch (Throwable ex)
4239                    {
4240                        fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
4241                    }
4242                }
4243            }
4244    
4245            public void refreshOrRemove()
4246            {
4247                try
4248                {
4249                    // Delete or refresh the bundle depending on its
4250                    // current state.
4251                    if (m_bundle.getState() == Bundle.UNINSTALLED)
4252                    {
4253                        m_bundle.closeAndDelete();
4254                        m_bundle = null;
4255                    }
4256                    else
4257                    {
4258                        // This removes all old bundle modules from memory and
4259                        // all old revisions from disk. It only maintains the
4260                        // newest version in the bundle cache.
4261                        refreshBundle(m_bundle);
4262                    }
4263                }
4264                catch (Throwable ex)
4265                {
4266                    fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
4267                }
4268            }
4269    
4270            public void restart()
4271            {
4272                if ((m_bundle != null) && (m_oldState == Bundle.ACTIVE))
4273                {
4274                    try
4275                    {
4276    // TODO: LAZY - Not sure if this is the best way...
4277                        int options = Bundle.START_TRANSIENT;
4278                        options = (m_bundle.getPersistentState() == Bundle.STARTING)
4279                            ? options | Bundle.START_ACTIVATION_POLICY
4280                            : options;
4281                        startBundle(m_bundle, options);
4282                    }
4283                    catch (Throwable ex)
4284                    {
4285                        fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
4286                    }
4287                }
4288            }
4289        }
4290    
4291        private static class ListenerHookRemovedCallback implements InvokeHookCallback
4292        {
4293            private final Collection /* ListenerHookInfo */ m_removed;
4294    
4295            ListenerHookRemovedCallback(Collection /* ListenerHookInfo */ removed)
4296            {
4297                m_removed = removed;
4298            }
4299    
4300            public void invokeHook(Object hook)
4301            {
4302                ((ListenerHook) hook).removed(m_removed);
4303            }
4304        }
4305    
4306        //
4307        // Locking related methods.
4308        //
4309    
4310        private void rememberUninstalledBundle(BundleImpl bundle)
4311        {
4312            synchronized (m_uninstalledBundlesLock_Priority3)
4313            {
4314                // Verify that the bundle is not already in the array.
4315                for (int i = 0;
4316                    (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
4317                    i++)
4318                {
4319                    if (m_uninstalledBundles[i] == bundle)
4320                    {
4321                        return;
4322                    }
4323                }
4324    
4325                if (m_uninstalledBundles != null)
4326                {
4327                    BundleImpl[] newBundles =
4328                        new BundleImpl[m_uninstalledBundles.length + 1];
4329                    System.arraycopy(m_uninstalledBundles, 0,
4330                        newBundles, 0, m_uninstalledBundles.length);
4331                    newBundles[m_uninstalledBundles.length] = bundle;
4332                    m_uninstalledBundles = newBundles;
4333                }
4334                else
4335                {
4336                    m_uninstalledBundles = new BundleImpl[] { bundle };
4337                }
4338            }
4339        }
4340    
4341        private void forgetUninstalledBundle(BundleImpl bundle)
4342        {
4343            synchronized (m_uninstalledBundlesLock_Priority3)
4344            {
4345                if (m_uninstalledBundles == null)
4346                {
4347                    return;
4348                }
4349    
4350                int idx = -1;
4351                for (int i = 0; i < m_uninstalledBundles.length; i++)
4352                {
4353                    if (m_uninstalledBundles[i] == bundle)
4354                    {
4355                        idx = i;
4356                        break;
4357                    }
4358                }
4359    
4360                if (idx >= 0)
4361                {
4362                    // If this is the only bundle, then point to empty list.
4363                    if ((m_uninstalledBundles.length - 1) == 0)
4364                    {
4365                        m_uninstalledBundles = new BundleImpl[0];
4366                    }
4367                    // Otherwise, we need to do some array copying.
4368                    else
4369                    {
4370                        BundleImpl[] newBundles =
4371                            new BundleImpl[m_uninstalledBundles.length - 1];
4372                        System.arraycopy(m_uninstalledBundles, 0, newBundles, 0, idx);
4373                        if (idx < newBundles.length)
4374                        {
4375                            System.arraycopy(
4376                                m_uninstalledBundles, idx + 1,
4377                                newBundles, idx, newBundles.length - idx);
4378                        }
4379                        m_uninstalledBundles = newBundles;
4380                    }
4381                }
4382            }
4383        }
4384    
4385        void acquireInstallLock(String location)
4386            throws BundleException
4387        {
4388            synchronized (m_installRequestLock_Priority1)
4389            {
4390                while (m_installRequestMap.get(location) != null)
4391                {
4392                    try
4393                    {
4394                        m_installRequestLock_Priority1.wait();
4395                    }
4396                    catch (InterruptedException ex)
4397                    {
4398                        throw new BundleException("Unable to install, thread interrupted.");
4399                    }
4400                }
4401    
4402                m_installRequestMap.put(location, location);
4403            }
4404        }
4405    
4406        void releaseInstallLock(String location)
4407        {
4408            synchronized (m_installRequestLock_Priority1)
4409            {
4410                m_installRequestMap.remove(location);
4411                m_installRequestLock_Priority1.notifyAll();
4412            }
4413        }
4414    
4415        void setBundleStateAndNotify(BundleImpl bundle, int state)
4416        {
4417            synchronized (m_bundleLock)
4418            {
4419                bundle.__setState(state);
4420                m_bundleLock.notifyAll();
4421            }
4422        }
4423    
4424        /**
4425         * This method acquires the lock for the specified bundle as long as the
4426         * bundle is in one of the specified states. If it is not, an exception
4427         * is thrown. Bundle state changes will be monitored to avoid deadlocks.
4428         * @param bundle The bundle to lock.
4429         * @param desiredStates Logically OR'ed desired bundle states.
4430         * @throws java.lang.IllegalStateException If the bundle is not in one of the
4431         *         specified desired states.
4432        **/
4433        void acquireBundleLock(BundleImpl bundle, int desiredStates)
4434            throws IllegalStateException
4435        {
4436            synchronized (m_bundleLock)
4437            {
4438                // Wait if the desired bundle is already locked by someone else
4439                // or if any thread has the global lock, unless the current thread
4440                // holds the global lock.
4441                while (!bundle.isLockable() ||
4442                    ((m_globalLockThread != null) && (m_globalLockThread != Thread.currentThread())))
4443                {
4444                    // Check to make sure the bundle is in a desired state.
4445                    // If so, keep waiting. If not, throw an exception.
4446                    if ((desiredStates & bundle.getState()) == 0)
4447                    {
4448                        throw new IllegalStateException("Bundle in unexpected state.");
4449                    }
4450                    // If the calling thread already owns the global lock, then make
4451                    // sure no other thread is trying to promote a bundle lock to a
4452                    // global lock. If so, interrupt the other thread to avoid deadlock.
4453                    else if (m_globalLockThread == Thread.currentThread()
4454                        && (bundle.getLockingThread() != null)
4455                        && m_globalLockWaitersList.contains(bundle.getLockingThread()))
4456                    {
4457                        bundle.getLockingThread().interrupt();
4458                    }
4459    
4460                    try
4461                    {
4462                        m_bundleLock.wait();
4463                    }
4464                    catch (InterruptedException ex)
4465                    {
4466                        // Ignore and just keep waiting.
4467                    }
4468                }
4469    
4470                // Now that we can acquire the bundle lock, let's check to make sure
4471                // it is in a desired state; if not, throw an exception and do not
4472                // lock it.
4473                if ((desiredStates & bundle.getState()) == 0)
4474                {
4475                    throw new IllegalStateException("Bundle in unexpected state.");
4476                }
4477    
4478                // Acquire the bundle lock.
4479                bundle.lock();
4480            }
4481        }
4482    
4483        /**
4484         * Releases the bundle's lock.
4485         * @param bundle The bundle whose lock is to be released.
4486         * @throws java.lang.IllegalStateException If the calling thread does not
4487         *         own the bundle lock.
4488        **/
4489        void releaseBundleLock(BundleImpl bundle)
4490        {
4491            synchronized (m_bundleLock)
4492            {
4493                // Unlock the bundle.
4494                bundle.unlock();
4495                // If the thread no longer holds the bundle lock,
4496                // then remove it from the held lock map.
4497                if (bundle.getLockingThread() == null)
4498                {
4499                    m_bundleLock.notifyAll();
4500                }
4501            }
4502        }
4503    
4504        /**
4505         * Promotes a bundle lock to the global lock. This is called by a thread
4506         * wanting the global lock, but already holding a bundle lock (currently
4507         * only when updating a bundle). Since it is possible to deadlock when
4508         * trying to acquire the global lock while holding a bundle lock, this
4509         * method may fail if a potential deadlock is detected.
4510         * @param bundle The bundle already locked by the calling thread.
4511         * @return <tt>true</tt> if the global lock was successfully acquired,
4512         *         <tt>false</tt> otherwise.
4513        **/
4514        private boolean acquireGlobalLock()
4515        {
4516            synchronized (m_bundleLock)
4517            {
4518                // Wait as long as some other thread holds the global lock
4519                // and the current thread is not interrupted.
4520                boolean interrupted = false;
4521                while (!interrupted
4522                    && (m_globalLockThread != null)
4523                    && (m_globalLockThread != Thread.currentThread()))
4524                {
4525                    // Add calling thread to global lock waiters list.
4526                    m_globalLockWaitersList.add(Thread.currentThread());
4527                    // We need to wake up all waiting threads so we can
4528                    // recheck for potential deadlock in acquireBundleLock()
4529                    // if this thread was holding a bundle lock and is now
4530                    // trying to promote it to a global lock.
4531                    m_bundleLock.notifyAll();
4532                    // Now wait for the global lock.
4533                    try
4534                    {
4535                        m_bundleLock.wait();
4536                    }
4537                    catch (InterruptedException ex)
4538                    {
4539                        interrupted = true;
4540                    }
4541                    // At this point we are either interrupted or will get the
4542                    // global lock, so remove the thread from the waiters list.
4543                    m_globalLockWaitersList.remove(Thread.currentThread());
4544                }
4545    
4546                // Check to see if we were interrupted, which means someone
4547                // with the global lock wants our bundle lock, so we should
4548                // fail gracefully.
4549                if (!interrupted)
4550                {
4551                    // Increment the current thread's global lock count.
4552                    m_globalLockCount++;
4553                    m_globalLockThread = Thread.currentThread();
4554                }
4555    
4556                // Note: If the thread was interrupted, there is no reason to notify
4557                // anyone, since the thread was likely interrupted to force it to give
4558                // up a bundle lock it is holding. When it does give up the bundle
4559                // lock, it will do a notifyAll() in there.
4560    
4561                return !interrupted;
4562            }
4563        }
4564    
4565        /**
4566         * Releases the global lock.
4567         * @throws java.lang.IllegalStateException If the calling thread does not
4568         *         own the global lock.
4569        **/
4570        private void releaseGlobalLock()
4571        {
4572            synchronized (m_bundleLock)
4573            {
4574                // Decrement the current thread's global lock count;
4575                if (m_globalLockThread == Thread.currentThread())
4576                {
4577                    m_globalLockCount--;
4578                    if (m_globalLockCount == 0)
4579                    {
4580                        m_globalLockThread = null;
4581                        m_bundleLock.notifyAll();
4582                    }
4583                }
4584                else
4585                {
4586                    throw new IllegalStateException(
4587                        "The current thread doesn't own the global lock.");
4588                }
4589            }
4590        }
4591    
4592        private volatile URLHandlersActivator m_urlHandlersActivator;
4593        
4594        void setURLHandlersActivator(URLHandlersActivator urlHandlersActivator)
4595        {
4596            m_urlHandlersActivator = urlHandlersActivator;
4597        }
4598        
4599        Object getStreamHandlerService(String protocol)
4600        {
4601            return m_urlHandlersActivator.getStreamHandlerService(protocol);
4602        }
4603        
4604        Object getContentHandlerService(String mimeType)
4605        {
4606            return m_urlHandlersActivator.getContentHandlerService(mimeType);
4607        }
4608    }