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 }