blob: a22d47d17a9f6a5c24e0eb4584ae10d241b1f663 [file] [log] [blame]
Richard S. Hall930fecc2005-08-16 18:33:34 +00001/*
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002 * Copyright 2006 The Apache Software Foundation
Richard S. Hall930fecc2005-08-16 18:33:34 +00003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
Richard S. Hall5a031592005-08-19 19:53:58 +000017package org.apache.felix.framework;
Richard S. Hall930fecc2005-08-16 18:33:34 +000018
19import java.io.*;
20import java.net.*;
Richard S. Hall930fecc2005-08-16 18:33:34 +000021import java.util.*;
22
Richard S. Hall5a031592005-08-19 19:53:58 +000023import org.apache.felix.framework.cache.*;
24import org.apache.felix.framework.searchpolicy.*;
25import org.apache.felix.framework.util.*;
Richard S. Hall5a031592005-08-19 19:53:58 +000026import org.apache.felix.moduleloader.*;
Richard S. Hall930fecc2005-08-16 18:33:34 +000027import org.osgi.framework.*;
28import org.osgi.service.packageadmin.ExportedPackage;
Richard S. Hall17897152006-03-02 13:43:09 +000029import org.osgi.service.startlevel.StartLevel;
Richard S. Hall930fecc2005-08-16 18:33:34 +000030
31public class Felix
32{
33 // Logging related member variables.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +000034 private Logger m_logger = new Logger();
Richard S. Hall930fecc2005-08-16 18:33:34 +000035 // Config properties.
36 private PropertyResolver m_config = new ConfigImpl();
37 // Configuration properties passed into constructor.
Richard S. Hallea415752005-12-05 19:30:28 +000038 private MutablePropertyResolver m_configMutable = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000039
Richard S. Hall29a4fbc2006-02-03 12:54:52 +000040 // MODULE FACTORY.
41 private IModuleFactory m_factory = null;
42 private R4SearchPolicyCore m_policyCore = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000043
44 // Object used as a lock when calculating which bundles
45 // when performing an operation on one or more bundles.
46 private Object[] m_bundleLock = new Object[0];
47
48 // Maps a bundle location to a bundle location;
49 // used to reserve a location when installing a bundle.
50 private Map m_installRequestMap = null;
51 // This lock must be acquired to modify m_installRequestMap;
52 // to help avoid deadlock this lock as priority 1 and should
53 // be acquired before locks with lower priority.
54 private Object[] m_installRequestLock_Priority1 = new Object[0];
55
56 // Maps a bundle location to a bundle.
57 private HashMap m_installedBundleMap = null;
58 // This lock must be acquired to modify m_installedBundleMap;
59 // to help avoid deadlock this lock as priority 2 and should
60 // be acquired before locks with lower priority.
61 private Object[] m_installedBundleLock_Priority2 = new Object[0];
62
63 // An array of uninstalled bundles before a refresh occurs.
64 private BundleImpl[] m_uninstalledBundles = null;
65 // This lock must be acquired to modify m_uninstalledBundles;
66 // to help avoid deadlock this lock as priority 3 and should
67 // be acquired before locks with lower priority.
68 private Object[] m_uninstalledBundlesLock_Priority3 = new Object[0];
69
70 // Status flag for framework.
71 public static final int INITIAL_STATUS = -1;
72 public static final int RUNNING_STATUS = 0;
73 public static final int STARTING_STATUS = 1;
74 public static final int STOPPING_STATUS = 2;
75 private int m_frameworkStatus = INITIAL_STATUS;
76
77 // Framework's active start level.
78 private int m_activeStartLevel =
79 FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
80
81 // Local file system cache.
Richard S. Hall04bdbb12006-03-15 14:26:15 +000082 private BundleCache m_cache = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000083
84 // Next available bundle identifier.
85 private long m_nextId = 1L;
Richard S. Hall441c7152006-02-17 11:07:10 +000086 private Object m_nextIdLock = new Object[0];
Richard S. Hall930fecc2005-08-16 18:33:34 +000087
88 // List of event listeners.
Richard S. Hall92770632006-07-24 10:18:52 +000089 private EventDispatcher m_dispatcher = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000090
91 // Service registry.
92 private ServiceRegistry m_registry = null;
93
Richard S. Hall29a4fbc2006-02-03 12:54:52 +000094 // Reusable bundle URL stream handler.
95 private URLStreamHandler m_bundleStreamHandler = null;
96
Richard S. Hall930fecc2005-08-16 18:33:34 +000097 /**
98 * <p>
99 * This method starts the framework instance; instances of the framework
100 * are dormant until this method is called. The caller may also provide
101 * <tt>MutablePropertyResolver</tt> implementations that the instance will
102 * use to obtain configuration or framework properties. Configuration
103 * properties are used internally by the framework and its extensions to alter
104 * its default behavior. Framework properties are used by bundles
105 * and are accessible from <tt>BundleContext.getProperty()</tt>.
106 * </p>
107 * <p>
108 * Configuration properties are the sole means to configure the framework's
109 * default behavior; the framework does not refer to any system properties for
110 * configuration information. If a <tt>MutablePropertyResolver</tt> is
111 * supplied to this method for configuration properties, then the framework will
112 * consult the <tt>MutablePropertyResolver</tt> instance for any and all
113 * configuration properties. It is possible to specify a <tt>null</tt>
114 * configuration property resolver, in which case the framework will use its
115 * default behavior in all cases. However, if the
116 * <a href="cache/DefaultBundleCache.html"><tt>DefaulBundleCache</tt></a>
117 * is used, then at a minimum a profile name or profile directory must
118 * be specified.
119 * </p>
120 * <p>
121 * The following configuration properties can be specified:
122 * </p>
123 * <ul>
Richard S. Hall930fecc2005-08-16 18:33:34 +0000124 * <li><tt>felix.auto.install.&lt;n&gt;</tt> - Space-delimited list of
125 * bundles to automatically install into start level <tt>n</tt> when
126 * the framework is started. Append a specific start level to this
127 * property name to assign the bundles' start level
128 * (e.g., <tt>felix.auto.install.2</tt>).
129 * </li>
130 * <li><tt>felix.auto.start.&lt;n&gt;</tt> - Space-delimited list of
131 * bundles to automatically install and start into start level
132 * <tt>n</tt> when the framework is started. Append a
133 * specific start level to this property name to assign the
134 * bundles' start level(e.g., <tt>felix.auto.start.2</tt>).
135 * </li>
136 * <li><tt>felix.startlevel.framework</tt> - The initial start level
137 * of the framework once it starts execution; the default
138 * value is 1.
139 * </li>
140 * <li><tt>felix.startlevel.bundle</tt> - The default start level for
141 * newly installed bundles; the default value is 1.
142 * </li>
Richard S. Hall5d226732005-11-08 09:09:05 +0000143 * <li><tt>framework.service.urlhandlers</tt> - Flag to indicate whether
144 * to activate the URL Handlers service for the framework instance;
145 * the default value is "<tt>true</tt>". Activating the URL Handlers
146 * service will result in the <tt>URL.setURLStreamHandlerFactory()</tt>
147 * and <tt>URLConnection.setContentHandlerFactory()</tt> being called.
148 * </li>
Richard S. Hall930fecc2005-08-16 18:33:34 +0000149 * <li><tt>felix.embedded.execution</tt> - Flag to indicate whether
150 * the framework is embedded into a host application; the default value is
151 * "<tt>false</tt>". If this flag is "<tt>true</tt>" then the framework
152 * will not called <tt>System.exit()</tt> upon termination.
153 * </li>
154 * <li><tt>felix.strict.osgi</tt> - Flag to indicate whether the framework is
155 * running in strict OSGi mode; the default value is "<tt>true</tt>".
156 * If this flag is "<tt>false</tt>" it enables a non-OSGi-compliant
157 * feature by persisting <tt>BundleActivator</tt>s that implement
158 * <tt>Serializable</tt>. This feature is not recommended since
159 * it is non-compliant.
160 * </li>
161 * </ul>
162 * <p>
163 * Besides the above framework configuration properties, it is also
164 * possible to specify properties for the bundle cache. The available
165 * bundle cache properties depend on the cache implementation
166 * being used. For the properties of the default bundle cache, refer to the
167 * <a href="cache/DefaultBundleCache.html"><tt>DefaulBundleCache</tt></a>
168 * API documentation.
169 * </p>
170 * <p>
171 * Framework properties are somewhat misnamed, since they are not used by
172 * the framework, but by bundles via <tt>BundleContext.getProperty()</tt>.
173 * Please refer to bundle documentation of your specific bundle for any
174 * available properties.
175 * </p>
176 * <p>
177 * The <a href="Main.html"><tt>Main</tt></a> class implements some
178 * functionality for default property file handling, which makes it
179 * possible to specify configuration properties and framework properties
180 * in files that are automatically loaded when starting the framework. If you
181 * plan to create your own framework instance, you may be
182 * able to take advantage of the features it provides; refer to its
183 * class documentation for more information.
184 * </p>
185 *
Richard S. Hallea415752005-12-05 19:30:28 +0000186 * @param configMutable An object for obtaining configuration properties,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000187 * may be <tt>null</tt>.
188 * @param frameworkProps An object for obtaining framework properties,
189 * may be <tt>null</tt>.
190 * @param activatorList A list of System Bundle activators.
191 **/
192 public synchronized void start(
Richard S. Hallea415752005-12-05 19:30:28 +0000193 MutablePropertyResolver configMutable,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000194 List activatorList)
195 {
196 if (m_frameworkStatus != INITIAL_STATUS)
197 {
198 throw new IllegalStateException("Invalid framework status: " + m_frameworkStatus);
199 }
200
201 // The framework is now in its startup sequence.
202 m_frameworkStatus = STARTING_STATUS;
203
204 // Initialize member variables.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000205 m_factory = null;
Richard S. Hallea415752005-12-05 19:30:28 +0000206 m_configMutable = (configMutable == null)
207 ? new MutablePropertyResolverImpl(new StringMap(false)) : configMutable;
Richard S. Hall930fecc2005-08-16 18:33:34 +0000208 m_activeStartLevel = FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
209 m_installRequestMap = new HashMap();
210 m_installedBundleMap = new HashMap();
211 m_uninstalledBundles = null;
212 m_cache = null;
213 m_nextId = 1L;
Richard S. Hall92770632006-07-24 10:18:52 +0000214 m_dispatcher = null;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000215 m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000216 m_registry = new ServiceRegistry(m_logger);
217
218 // Add a listener to the service registry; this is
219 // used to distribute service registry events to
220 // service listeners.
221 m_registry.addServiceListener(new ServiceListener() {
222 public void serviceChanged(ServiceEvent event)
223 {
224 fireServiceEvent(event);
225 }
226 });
227
Richard S. Hall930fecc2005-08-16 18:33:34 +0000228 try
229 {
Richard S. Hall04bdbb12006-03-15 14:26:15 +0000230 m_cache = new BundleCache(m_config, m_logger);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000231 }
232 catch (Exception ex)
233 {
234 System.err.println("Error creating bundle cache:");
235 ex.printStackTrace();
236
237 // Only shutdown the JVM if the framework is running stand-alone.
238 String embedded = m_config.get(
239 FelixConstants.EMBEDDED_EXECUTION_PROP);
240 boolean isEmbedded = (embedded == null)
241 ? false : embedded.equals("true");
242 if (!isEmbedded)
243 {
Karl Paulsc19abb42006-07-21 10:23:11 +0000244 if (System.getSecurityManager() != null)
245 {
246 java.security.AccessController.doPrivileged(
247 new java.security.PrivilegedAction()
248 {
249 public Object run()
250 {
251 System.exit(-1);
252
253 return null;
254 }
255 });
256 }
257 else
258 {
259 System.exit(-1);
260 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000261 }
262 else
263 {
264 throw new RuntimeException(ex.toString());
265 }
266 }
267
268 // Create search policy for module loader.
Richard S. Halle975d4d2006-04-10 12:56:14 +0000269 m_policyCore = new R4SearchPolicyCore(m_logger, m_config);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000270
271 // Add a resolver listener to the search policy
272 // so that we will be notified when modules are resolved
273 // in order to update the bundle state.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000274 m_policyCore.addResolverListener(new ResolveListener() {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000275 public void moduleResolved(ModuleEvent event)
276 {
277 BundleImpl bundle = null;
278 try
279 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000280 long id = Util.getBundleIdFromModuleId(
Richard S. Hall930fecc2005-08-16 18:33:34 +0000281 event.getModule().getId());
282 if (id >= 0)
283 {
284 // Update the bundle's state to resolved when the
285 // current module is resolved; just ignore resolve
286 // events for older revisions since this only occurs
287 // when an update is done on an unresolved bundle
288 // and there was no refresh performed.
289 bundle = (BundleImpl) getBundle(id);
290
291 // Lock the bundle first.
292 try
293 {
294 acquireBundleLock(bundle);
295 if (bundle.getInfo().getCurrentModule() == event.getModule())
296 {
297 bundle.getInfo().setState(Bundle.RESOLVED);
298 }
299 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000300 finally
301 {
302 releaseBundleLock(bundle);
303 }
304 }
305 }
306 catch (NumberFormatException ex)
307 {
308 // Ignore.
309 }
310 }
311
312 public void moduleUnresolved(ModuleEvent event)
313 {
314 // We can ignore this, because the only time it
315 // should happen is when a refresh occurs. The
316 // refresh operation resets the bundle's state
317 // by calling BundleInfo.reset(), thus it is not
318 // necessary for us to reset the bundle's state
319 // here.
320 }
321 });
322
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000323 m_factory = new ModuleFactoryImpl(m_logger);
324 m_policyCore.setModuleFactory(m_factory);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000325
Richard S. Hall92770632006-07-24 10:18:52 +0000326 // Initialize event dispatcher.
327 m_dispatcher = new EventDispatcher(m_logger);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000328
329 // Initialize framework properties.
330 initializeFrameworkProperties();
331
332 // Before we reload any cached bundles, let's create a system
333 // bundle that is responsible for providing specific container
334 // related services.
335 SystemBundle systembundle = null;
336 try
337 {
338 // Create a simple bundle info for the system bundle.
339 BundleInfo info = new BundleInfo(
340 m_logger, new SystemBundleArchive(), null);
341 systembundle = new SystemBundle(this, info, activatorList);
Richard S. Hall594145f2006-07-23 13:07:18 +0000342 // Create a module for the system bundle.
343 IModuleDefinition md = new ModuleDefinition(
344 systembundle.getExports(), null, null, null);
345 systembundle.getInfo().addModule(m_factory.createModule("0", md));
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000346 systembundle.getContentLoader().setSearchPolicy(
347 new R4SearchPolicy(
348 m_policyCore, systembundle.getInfo().getCurrentModule()));
349 m_factory.setContentLoader(
350 systembundle.getInfo().getCurrentModule(),
351 systembundle.getContentLoader());
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000352
Richard S. Hall930fecc2005-08-16 18:33:34 +0000353 m_installedBundleMap.put(
354 systembundle.getInfo().getLocation(), systembundle);
355
356 // Manually resolve the System Bundle, which will cause its
357 // state to be set to RESOLVED.
358 try
359 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000360 m_policyCore.resolve(systembundle.getInfo().getCurrentModule());
Richard S. Hall930fecc2005-08-16 18:33:34 +0000361 }
362 catch (ResolveException ex)
363 {
364 // This should never happen.
365 throw new BundleException(
366 "Unresolved package in System Bundle:"
367 + ex.getPackage());
368 }
369
370 // Start the system bundle; this will set its state
371 // to STARTING, we must set its state to ACTIVE after
372 // all bundles are restarted below according to the spec.
373 systembundle.start();
374 }
375 catch (Exception ex)
376 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000377 m_factory = null;
Richard S. Hall92770632006-07-24 10:18:52 +0000378 EventDispatcher.shutdown();
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000379 m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000380 throw new RuntimeException("Unable to start system bundle.");
381 }
382
383 // Reload and cached bundles.
Richard S. Hall04bdbb12006-03-15 14:26:15 +0000384 BundleArchive[] archives = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +0000385
386 // First get cached bundle identifiers.
387 try
388 {
389 archives = m_cache.getArchives();
390 }
391 catch (Exception ex)
392 {
393 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000394 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000395 "Unable to list saved bundles: " + ex, ex);
396 archives = null;
397 }
398
399 BundleImpl bundle = null;
400
401 // Now install all cached bundles.
402 for (int i = 0; (archives != null) && (i < archives.length); i++)
403 {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000404 try
405 {
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000406 // Make sure our id generator is not going to overlap.
407 // TODO: This is not correct since it may lead to re-used
408 // ids, which is not okay according to OSGi.
409 m_nextId = Math.max(m_nextId, archives[i].getId() + 1);
410
Richard S. Hall930fecc2005-08-16 18:33:34 +0000411 // It is possible that a bundle in the cache was previously
412 // uninstalled, but not completely deleted (perhaps because
413 // of a crash or a locked file), so if we see an archive
414 // with an UNINSTALLED persistent state, then try to remove
415 // it now.
416 if (archives[i].getPersistentState() == Bundle.UNINSTALLED)
417 {
418 m_cache.remove(archives[i]);
419 }
420 // Otherwise re-install the cached bundle.
421 else
422 {
423 // Install the cached bundle.
424 bundle = (BundleImpl) installBundle(
425 archives[i].getId(), archives[i].getLocation(), null);
426 }
427 }
428 catch (Exception ex)
429 {
430 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
431 try
432 {
433 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000434 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000435 "Unable to re-install " + archives[i].getLocation(),
436 ex);
437 }
438 catch (Exception ex2)
439 {
440 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000441 Logger.LOG_ERROR,
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000442 "Unable to re-install cached bundle.",
Richard S. Hall930fecc2005-08-16 18:33:34 +0000443 ex);
444 }
445 // TODO: Perhaps we should remove the cached bundle?
446 }
447 }
448
449 // Get the framework's default start level.
450 int startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
451 String s = m_config.get(FelixConstants.FRAMEWORK_STARTLEVEL_PROP);
452 if (s != null)
453 {
454 try
455 {
456 startLevel = Integer.parseInt(s);
457 }
458 catch (NumberFormatException ex)
459 {
460 startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
461 }
462 }
463
464 // Load bundles from auto-install and auto-start properties;
465 processAutoProperties();
466
Richard S. Hall17897152006-03-02 13:43:09 +0000467 // Set the start level using the start level service;
468 // this ensures that all start level requests are
469 // serialized.
470 // NOTE: There is potentially a specification compliance
471 // issue here, since the start level request is asynchronous;
472 // this means that the framework will fire its STARTED event
473 // before all bundles have officially been restarted and it
474 // is not clear if this is really an issue or not.
475 try
476 {
477 StartLevel sl = (StartLevel) getService(
478 getBundle(0),
479 getServiceReferences((BundleImpl) getBundle(0), StartLevel.class.getName(), null)[0]);
480 sl.setStartLevel(startLevel);
481 }
482 catch (InvalidSyntaxException ex)
483 {
484 // Should never happen.
485 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000486
487 // The framework is now running.
488 m_frameworkStatus = RUNNING_STATUS;
489
490 // Set the system bundle state to ACTIVE.
491 systembundle.getInfo().setState(Bundle.ACTIVE);
492
493 // Fire started event for system bundle.
494 fireBundleEvent(BundleEvent.STARTED, systembundle);
495
496 // Send a framework event to indicate the framework has started.
497 fireFrameworkEvent(FrameworkEvent.STARTED, getBundle(0), null);
498 }
499
500 /**
501 * This method cleanly shuts down the framework, it must be called at the
502 * end of a session in order to shutdown all active bundles.
503 **/
504 public synchronized void shutdown()
505 {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000506 // Change framework status from running to stopping.
507 // If framework is not running, then just return.
508 if (m_frameworkStatus != RUNNING_STATUS)
509 {
510 return;
511 }
512
513 // The framework is now in its shutdown sequence.
514 m_frameworkStatus = STOPPING_STATUS;
515
Richard S. Hall17897152006-03-02 13:43:09 +0000516 // Use the start level service to set the start level to zero
517 // in order to stop all bundles in the framework. Since framework
518 // shutdown happens on its own thread, we can wait for the start
519 // level service to finish before proceeding by calling the
520 // non-spec setStartLevelAndWait() method.
521 try
522 {
523 StartLevelImpl sl = (StartLevelImpl) getService(
524 getBundle(0),
525 getServiceReferences((BundleImpl) getBundle(0), StartLevel.class.getName(), null)[0]);
526 sl.setStartLevelAndWait(0);
527 }
528 catch (InvalidSyntaxException ex)
529 {
530 // Should never happen.
531 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000532
533 // Just like initialize() called the system bundle's start()
534 // method, we must call its stop() method here so that it
535 // can perform any necessary clean up.
536 try
537 {
538 getBundle(0).stop();
539 }
540 catch (Exception ex)
541 {
542 fireFrameworkEvent(FrameworkEvent.ERROR, getBundle(0), ex);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000543 m_logger.log(Logger.LOG_ERROR, "Error stopping system bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000544 }
545
Richard S. Hall60c26d42006-07-19 10:35:04 +0000546 // Since they may be updated and uninstalled bundles that
547 // have not been refreshed, we will take care of refreshing
548 // them during shutdown.
549
550 // First loop through all bundled and purge old revisions
551 // from updated bundles.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000552 Bundle[] bundles = getBundles();
553 for (int i = 0; i < bundles.length; i++)
554 {
555 BundleImpl bundle = (BundleImpl) bundles[i];
Richard S. Hall60c26d42006-07-19 10:35:04 +0000556 if (bundle.getInfo().getArchive().getRevisionCount() > 1)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000557 {
558 try
559 {
560 purgeBundle(bundle);
561 }
562 catch (Exception ex)
563 {
564 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000565 m_logger.log(Logger.LOG_ERROR, "Unable to purge bundle "
Richard S. Hall930fecc2005-08-16 18:33:34 +0000566 + bundle.getInfo().getLocation(), ex);
567 }
568 }
569 }
570
Richard S. Hall60c26d42006-07-19 10:35:04 +0000571 // Next garbage collection any uninstalled bundles.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000572 for (int i = 0;
573 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
574 i++)
575 {
576 try
577 {
578 garbageCollectBundle(m_uninstalledBundles[i]);
579 }
580 catch (Exception ex)
581 {
582 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000583 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000584 "Unable to remove "
585 + m_uninstalledBundles[i].getInfo().getLocation(), ex);
586 }
587 }
588
589 // Shutdown event dispatching queue.
Richard S. Hall92770632006-07-24 10:18:52 +0000590 EventDispatcher.shutdown();
Richard S. Hall930fecc2005-08-16 18:33:34 +0000591
592 // The framework is no longer in a usable state.
593 m_frameworkStatus = INITIAL_STATUS;
Richard S. Hall3331ad72006-06-20 09:07:23 +0000594
595 // Remove all bundles from the module factory so that any
596 // open resources will be closed.
597 bundles = getBundles();
598 for (int i = 0; i < bundles.length; i++)
599 {
600 BundleImpl bundle = (BundleImpl) bundles[i];
601 try
602 {
603 IModule[] modules = bundle.getInfo().getModules();
604 for (int j = 0; j < modules.length; j++)
605 {
606 m_factory.removeModule(modules[j]);
607 }
608 }
609 catch (Exception ex)
610 {
611 m_logger.log(Logger.LOG_ERROR,
612 "Unable to clean up " + bundle.getInfo().getLocation(), ex);
613 }
614 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000615 }
616
617 public int getStatus()
618 {
619 return m_frameworkStatus;
620 }
621
622 /**
623 * Returns the active start level of the framework; this method
624 * implements functionality for the Start Level service.
625 * @return The active start level of the framework.
626 **/
627 protected int getStartLevel()
628 {
629 return m_activeStartLevel;
630 }
631
632 /**
633 * Implements the functionality of the <tt>setStartLevel()</tt>
634 * method for the StartLevel service, but does not do the security or
635 * parameter check. The security and parameter check are done in the
636 * StartLevel service implementation because this method is called on
637 * a separate thread and the caller's thread would already be gone if
Richard S. Hall17897152006-03-02 13:43:09 +0000638 * we did the checks in this method. This method should not be called
639 * directly.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000640 * @param requestedLevel The new start level of the framework.
641 **/
Richard S. Hall441c7152006-02-17 11:07:10 +0000642 protected void setFrameworkStartLevel(int requestedLevel)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000643 {
Richard S. Hall17897152006-03-02 13:43:09 +0000644 Bundle[] bundles = null;
645
646 // Synchronization for changing the start level is rather loose.
647 // The install lock is grabbed initially to atomically change the
648 // framework's start level and to grab a sorted snapshot of the
649 // currently installed bundles, but then this lock is freed immediately.
650 // No locks are held while processing the currently installed bundles
651 // for starting/stopping based on the new start level. The only locking
652 // that occurs is for individual bundles when startBundle()/stopBundle()
653 // is called, but this locking is done in the respective method.
654 //
655 // This approach does mean that it is possible for a for individual
656 // bundle states to change during this operation. For example, bundle
657 // start levels can be changed or bundles can be uninstalled. If a
658 // bundle's start level changes, then it is possible for it to be
659 // processed out of order. Uninstalled bundles are just logged and
660 // ignored. I had a bit of discussion with Peter Kriens about these
661 // issues and he felt they were consistent with the spec, which
662 // intended Start Level to have some leeway.
663 //
664 // Calls to this method are only made by the start level thread, which
665 // serializes framework start level changes. Thus, it is not possible
666 // for two requests to change the framework's start level to interfere
667 // with each other.
668
669 synchronized (m_installedBundleLock_Priority2)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000670 {
Richard S. Hall17897152006-03-02 13:43:09 +0000671 // Determine if we are lowering or raising the
672 // active start level.
673 boolean lowering = (requestedLevel < m_activeStartLevel);
674
675 // Record new start level.
676 m_activeStartLevel = requestedLevel;
677
678 // Get a snapshot of all installed bundles.
679 bundles = getBundles();
680
681 // Sort bundle array by start level either ascending or
682 // descending depending on whether the start level is being
683 // lowered or raised to that the bundles can be efficiently
Richard S. Hall5259e3e2006-07-14 18:55:59 +0000684 // processed in order. Within a start level sort by bundle ID.
Richard S. Hall17897152006-03-02 13:43:09 +0000685 Comparator comparator = null;
686 if (lowering)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000687 {
Richard S. Hall17897152006-03-02 13:43:09 +0000688 // Sort descending to stop highest start level first.
689 comparator = new Comparator() {
690 public int compare(Object o1, Object o2)
Richard S. Hall441c7152006-02-17 11:07:10 +0000691 {
Richard S. Hall17897152006-03-02 13:43:09 +0000692 BundleImpl b1 = (BundleImpl) o1;
693 BundleImpl b2 = (BundleImpl) o2;
694 if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
695 < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
696 {
697 return 1;
698 }
699 else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
700 > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
701 {
702 return -1;
703 }
Richard S. Hall5259e3e2006-07-14 18:55:59 +0000704 else if (b1.getInfo().getBundleId() < b2.getInfo().getBundleId())
705 {
706 return 1;
707 }
708 return -1;
Richard S. Hall441c7152006-02-17 11:07:10 +0000709 }
Richard S. Hall17897152006-03-02 13:43:09 +0000710 };
711 }
712 else
713 {
714 // Sort ascending to start lowest start level first.
715 comparator = new Comparator() {
716 public int compare(Object o1, Object o2)
Richard S. Hall441c7152006-02-17 11:07:10 +0000717 {
Richard S. Hall17897152006-03-02 13:43:09 +0000718 BundleImpl b1 = (BundleImpl) o1;
719 BundleImpl b2 = (BundleImpl) o2;
720 if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
721 > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
Richard S. Hall441c7152006-02-17 11:07:10 +0000722 {
Richard S. Hall17897152006-03-02 13:43:09 +0000723 return 1;
Richard S. Hall441c7152006-02-17 11:07:10 +0000724 }
Richard S. Hall17897152006-03-02 13:43:09 +0000725 else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
726 < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
Richard S. Hall441c7152006-02-17 11:07:10 +0000727 {
Richard S. Hall17897152006-03-02 13:43:09 +0000728 return -1;
Richard S. Hall441c7152006-02-17 11:07:10 +0000729 }
Richard S. Hall5259e3e2006-07-14 18:55:59 +0000730 else if (b1.getInfo().getBundleId() > b2.getInfo().getBundleId())
731 {
732 return 1;
733 }
734 return -1;
Richard S. Hall17897152006-03-02 13:43:09 +0000735 }
736 };
737 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000738
Richard S. Hall17897152006-03-02 13:43:09 +0000739 Arrays.sort(bundles, comparator);
740 }
741
742 // Stop or start the bundles according to the start level.
743 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
744 {
745 BundleImpl impl = (BundleImpl) bundles[i];
746
747 // Ignore the system bundle, since its start() and
748 // stop() methods get called explicitly in Felix.start()
749 // and Felix.shutdown(), respectively.
750 if (impl.getInfo().getBundleId() == 0)
751 {
752 continue;
753 }
754
755 // Lock the current bundle.
756 acquireBundleLock(impl);
757
758 try
759 {
760 // Start the bundle if necessary.
761 if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
762 (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
763 <= m_activeStartLevel))
764 {
765 try
766 {
767 startBundle(impl, false);
768 }
769 catch (Throwable th)
770 {
771 fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
772 m_logger.log(
773 Logger.LOG_ERROR,
774 "Error starting " + impl.getInfo().getLocation(), th);
Richard S. Hall441c7152006-02-17 11:07:10 +0000775 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000776 }
Richard S. Hall17897152006-03-02 13:43:09 +0000777 // Stop the bundle if necessary.
778 else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
779 > m_activeStartLevel)
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000780 {
Richard S. Hall17897152006-03-02 13:43:09 +0000781 try
Richard S. Hall441c7152006-02-17 11:07:10 +0000782 {
Richard S. Hall17897152006-03-02 13:43:09 +0000783 stopBundle(impl, false);
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000784 }
Richard S. Hall17897152006-03-02 13:43:09 +0000785 catch (Throwable th)
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000786 {
Richard S. Hall17897152006-03-02 13:43:09 +0000787 fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
788 m_logger.log(
789 Logger.LOG_ERROR,
790 "Error stopping " + impl.getInfo().getLocation(), th);
Richard S. Hall441c7152006-02-17 11:07:10 +0000791 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000792 }
Richard S. Hall17897152006-03-02 13:43:09 +0000793 }
794 finally
795 {
796 // Always release bundle lock.
797 releaseBundleLock(impl);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000798 }
799 }
800
801 fireFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, getBundle(0), null);
802 }
803
804 /**
805 * Returns the start level into which newly installed bundles will
806 * be placed by default; this method implements functionality for
807 * the Start Level service.
808 * @return The default start level for newly installed bundles.
809 **/
810 protected int getInitialBundleStartLevel()
811 {
812 String s = m_config.get(FelixConstants.BUNDLE_STARTLEVEL_PROP);
813
814 if (s != null)
815 {
816 try
817 {
818 int i = Integer.parseInt(s);
819 return (i > 0) ? i : FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
820 }
821 catch (NumberFormatException ex)
822 {
823 // Ignore and return the default value.
824 }
825 }
826 return FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
827 }
828
829 /**
830 * Sets the default start level into which newly installed bundles
831 * will be placed; this method implements functionality for the Start
832 * Level service.
833 * @param startLevel The new default start level for newly installed
834 * bundles.
835 * @throws java.lang.IllegalArgumentException If the specified start
836 * level is not greater than zero.
837 * @throws java.security.SecurityException If the caller does not
838 * have <tt>AdminPermission</tt>.
839 **/
840 protected void setInitialBundleStartLevel(int startLevel)
841 {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000842 if (startLevel <= 0)
843 {
844 throw new IllegalArgumentException(
845 "Initial start level must be greater than zero.");
846 }
847
Richard S. Hallea415752005-12-05 19:30:28 +0000848 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +0000849 FelixConstants.BUNDLE_STARTLEVEL_PROP, Integer.toString(startLevel));
850 }
851
852 /**
853 * Returns the start level for the specified bundle; this method
854 * implements functionality for the Start Level service.
855 * @param bundle The bundle to examine.
856 * @return The start level of the specified bundle.
857 * @throws java.lang.IllegalArgumentException If the specified
858 * bundle has been uninstalled.
859 **/
860 protected int getBundleStartLevel(Bundle bundle)
861 {
862 if (bundle.getState() == Bundle.UNINSTALLED)
863 {
864 throw new IllegalArgumentException("Bundle is uninstalled.");
865 }
866
867 return ((BundleImpl) bundle).getInfo().getStartLevel(getInitialBundleStartLevel());
868 }
869
870 /**
871 * Sets the start level of the specified bundle; this method
872 * implements functionality for the Start Level service.
873 * @param bundle The bundle whose start level is to be modified.
874 * @param startLevel The new start level of the specified bundle.
875 * @throws java.lang.IllegalArgumentException If the specified
876 * bundle is the system bundle or if the bundle has been
877 * uninstalled.
878 * @throws java.security.SecurityException If the caller does not
879 * have <tt>AdminPermission</tt>.
880 **/
881 protected void setBundleStartLevel(Bundle bundle, int startLevel)
882 {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000883 // Acquire bundle lock.
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000884 acquireBundleLock((BundleImpl) bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000885
886 Throwable rethrow = null;
887
888 try
889 {
890 if (bundle.getState() == Bundle.UNINSTALLED)
891 {
892 throw new IllegalArgumentException("Bundle is uninstalled.");
893 }
894
895 if (startLevel >= 1)
896 {
897 BundleImpl impl = (BundleImpl) bundle;
898 impl.getInfo().setStartLevel(startLevel);
899
900 try
901 {
902 // Start the bundle if necessary.
903 if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
904 (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
905 <= m_activeStartLevel))
906 {
907 startBundle(impl, false);
908 }
909 // Stop the bundle if necessary.
910 else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
911 > m_activeStartLevel)
912 {
913 stopBundle(impl, false);
914 }
915 }
916 catch (Throwable th)
917 {
918 rethrow = th;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000919 m_logger.log(Logger.LOG_ERROR, "Error starting/stopping bundle.", th);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000920 }
921 }
922 else
923 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000924 m_logger.log(Logger.LOG_WARNING, "Bundle start level must be greater than zero.");
Richard S. Hall930fecc2005-08-16 18:33:34 +0000925 }
926 }
927 finally
928 {
929 // Always release bundle lock.
930 releaseBundleLock((BundleImpl) bundle);
931 }
932
933 if (rethrow != null)
934 {
935 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, rethrow);
936 }
937 }
938
939 /**
940 * Returns whether a bundle is persistently started; this is an
941 * method implementation for the Start Level service.
942 * @param bundle The bundle to examine.
943 * @return <tt>true</tt> if the bundle is marked as persistently
944 * started, <tt>false</tt> otherwise.
945 * @throws java.lang.IllegalArgumentException If the specified
946 * bundle has been uninstalled.
947 **/
948 protected boolean isBundlePersistentlyStarted(Bundle bundle)
949 {
950 if (bundle.getState() == Bundle.UNINSTALLED)
951 {
952 throw new IllegalArgumentException("Bundle is uninstalled.");
953 }
954
955 return (((BundleImpl) bundle).getInfo().getPersistentState() == Bundle.ACTIVE);
956 }
957
958 //
959 // Implementation of Bundle interface methods.
960 //
961
962 /**
963 * Implementation for Bundle.getHeaders().
964 **/
965 protected Dictionary getBundleHeaders(BundleImpl bundle)
966 {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000967 return new MapToDictionary(bundle.getInfo().getCurrentHeader());
968 }
969
970 /**
971 * Implementation for Bundle.getLocation().
972 **/
973 protected String getBundleLocation(BundleImpl bundle)
974 {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000975 return bundle.getInfo().getLocation();
976 }
977
978 /**
979 * Implementation for Bundle.getResource().
980 **/
981 protected URL getBundleResource(BundleImpl bundle, String name)
982 {
983 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
984 {
985 throw new IllegalStateException("The bundle is uninstalled.");
986 }
Richard S. Hall001cc302006-02-03 15:03:24 +0000987 return bundle.getInfo().getCurrentModule().getResource(name);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000988 }
989
Richard S. Hallbcbf83e2006-02-05 13:28:26 +0000990 /**
991 * Implementation for Bundle.getEntry().
992 **/
993 protected URL getBundleEntry(BundleImpl bundle, String name)
994 {
995 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
996 {
997 throw new IllegalStateException("The bundle is uninstalled.");
998 }
Richard S. Hallbcbf83e2006-02-05 13:28:26 +0000999 return ((ContentLoaderImpl) bundle.getInfo().getCurrentModule()
1000 .getContentLoader()).getResourceFromContent(name);
1001 }
1002
Richard S. Hall4f09b642006-02-06 10:59:19 +00001003 /**
1004 * Implementation for Bundle.getEntryPaths().
1005 **/
1006 protected Enumeration getBundleEntryPaths(BundleImpl bundle, String path)
1007 {
1008 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1009 {
1010 throw new IllegalStateException("The bundle is uninstalled.");
1011 }
Richard S. Hall6fa05d02006-07-21 08:24:12 +00001012
1013 // Get the entry enumeration from the module content and
1014 // create a wrapper enumeration to filter it.
1015 Enumeration enumeration = new GetEntryPathsEnumeration(bundle, path);
1016
1017 // Return the enumeration if it has elements.
1018 return (!enumeration.hasMoreElements()) ? null : enumeration;
Richard S. Hall4f09b642006-02-06 10:59:19 +00001019 }
1020
Richard S. Hall4d2f3972006-07-20 15:58:17 +00001021 /**
1022 * Implementation for findEntries().
1023 **/
1024 public Enumeration findBundleEntries(
1025 BundleImpl bundle, String path, String filePattern, boolean recurse)
1026 {
Richard S. Hall4d2f3972006-07-20 15:58:17 +00001027 // Try to resolve the bundle per the spec.
1028 resolveBundles(new Bundle[] { bundle });
1029
Richard S. Hall6fa05d02006-07-21 08:24:12 +00001030 // Get the entry enumeration from the module content and
1031 // create a wrapper enumeration to filter it.
1032 Enumeration enumeration =
1033 new FindEntriesEnumeration(bundle, path, filePattern, recurse);
Richard S. Hall4d2f3972006-07-20 15:58:17 +00001034
Richard S. Hall6fa05d02006-07-21 08:24:12 +00001035 // Return the enumeration if it has elements.
1036 return (!enumeration.hasMoreElements()) ? null : enumeration;
Richard S. Hall4d2f3972006-07-20 15:58:17 +00001037 }
1038
Richard S. Hall930fecc2005-08-16 18:33:34 +00001039 protected ServiceReference[] getBundleRegisteredServices(BundleImpl bundle)
1040 {
1041 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1042 {
1043 throw new IllegalStateException("The bundle is uninstalled.");
1044 }
1045
1046 // Filter list of registered service references.
1047 ServiceReference[] refs = m_registry.getRegisteredServices(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001048
Karl Paulsc19abb42006-07-21 10:23:11 +00001049 return refs;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001050 }
1051
1052 protected ServiceReference[] getBundleServicesInUse(Bundle bundle)
1053 {
1054 // Filter list of "in use" service references.
1055 ServiceReference[] refs = m_registry.getServicesInUse(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001056
Karl Paulsc19abb42006-07-21 10:23:11 +00001057 return refs;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001058 }
1059
1060 protected boolean bundleHasPermission(BundleImpl bundle, Object obj)
1061 {
1062 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1063 {
1064 throw new IllegalStateException("The bundle is uninstalled.");
1065 }
1066
Richard S. Hall2cf44c92006-01-23 19:23:56 +00001067 if (System.getSecurityManager() != null)
Richard S. Hall65730962006-01-23 19:23:13 +00001068 {
1069 try
1070 {
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001071 return (obj instanceof java.security.Permission)
1072 ? java.security.Policy.getPolicy().getPermissions(
Richard S. Hall65730962006-01-23 19:23:13 +00001073 new java.security.CodeSource(
Richard S. Hallc762b692006-01-27 15:18:57 +00001074 new java.net.URL(bundle.getInfo().getLocation()),
1075 (java.security.cert.Certificate[]) null))
Richard S. Hall65730962006-01-23 19:23:13 +00001076 .implies((java.security.Permission) obj)
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001077 : false;
Richard S. Hall65730962006-01-23 19:23:13 +00001078 }
1079 catch (Exception ex)
1080 {
1081 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001082 Logger.LOG_WARNING,
Richard S. Hall65730962006-01-23 19:23:13 +00001083 "Exception while evaluating the permission.",
1084 ex);
1085 return false;
1086 }
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001087 }
Richard S. Hall65730962006-01-23 19:23:13 +00001088
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001089 return true;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001090 }
1091
1092 /**
Richard S. Hall74b97972005-11-30 15:51:41 +00001093 * Implementation for Bundle.loadClass().
1094 **/
1095 protected Class loadBundleClass(BundleImpl bundle, String name) throws ClassNotFoundException
1096 {
Richard S. Hallf1359482006-02-14 08:02:51 +00001097 Class clazz = bundle.getInfo().getCurrentModule().getClass(name);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001098 if (clazz == null)
Richard S. Hall74b97972005-11-30 15:51:41 +00001099 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001100 // Throw exception.
1101 ClassNotFoundException ex = new ClassNotFoundException(name);
1102
Richard S. Hall624f8012005-11-30 15:53:43 +00001103 // The spec says we must fire a framework error.
Richard S. Hall74b97972005-11-30 15:51:41 +00001104 fireFrameworkEvent(
1105 FrameworkEvent.ERROR, bundle,
1106 new BundleException(ex.getMessage()));
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001107
Richard S. Hall74b97972005-11-30 15:51:41 +00001108 throw ex;
1109 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001110 return clazz;
Richard S. Hall74b97972005-11-30 15:51:41 +00001111 }
1112
1113 /**
Richard S. Hall930fecc2005-08-16 18:33:34 +00001114 * Implementation for Bundle.start().
1115 **/
1116 protected void startBundle(BundleImpl bundle, boolean record)
1117 throws BundleException
1118 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001119 // CONCURRENCY NOTE:
1120 // Starting a bundle may actually impact many bundles, since
1121 // the bundle being started my need to be resolved, which in
1122 // turn may need to resolve other bundles. Despite this fact,
1123 // we only acquire the lock for the bundle being started, because
1124 // when resolve is called on this bundle, it will eventually
1125 // call resolve on the module loader search policy, which does
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001126 // its own locking on the module factory instance. Since the
1127 // resolve algorithm is locking the module factory instance, it
Richard S. Hall930fecc2005-08-16 18:33:34 +00001128 // is not possible for other bundles to be installed or removed,
1129 // so we don't have to worry about these possibilities.
1130 //
1131 // Further, if other bundles are started during this operation,
1132 // then either they will resolve first because they got the lock
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001133 // on the module factory or we will resolve first since we got
1134 // the lock on the module factory, so there should be no interference.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001135 // If other bundles are stopped or uninstalled, this should pose
1136 // no problems, since this does not impact their resolved state.
1137 // If a refresh occurs, then the refresh algorithm ulimately has
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001138 // to acquire the module factory instance lock too before it can
Richard S. Hall930fecc2005-08-16 18:33:34 +00001139 // completely purge old modules, so it should also complete either
1140 // before or after this bundle is started. At least that's the
1141 // theory.
1142
1143 // Acquire bundle lock.
1144 acquireBundleLock(bundle);
1145
1146 try
1147 {
1148 _startBundle(bundle, record);
1149 }
1150 finally
1151 {
1152 // Release bundle lock.
1153 releaseBundleLock(bundle);
1154 }
1155 }
1156
1157 private void _startBundle(BundleImpl bundle, boolean record)
1158 throws BundleException
1159 {
1160 // Set and save the bundle's persistent state to active
1161 // if we are supposed to record state change.
1162 if (record)
1163 {
1164 bundle.getInfo().setPersistentStateActive();
1165 }
1166
1167 // Try to start the bundle.
1168 BundleInfo info = bundle.getInfo();
1169
1170 // Ignore bundles whose persistent state is not active
1171 // or whose start level is greater than the framework's.
1172 if ((info.getPersistentState() != Bundle.ACTIVE)
1173 || (info.getStartLevel(getInitialBundleStartLevel()) > getStartLevel()))
1174 {
1175 return;
1176 }
1177
1178 switch (info.getState())
1179 {
1180 case Bundle.UNINSTALLED:
1181 throw new IllegalStateException("Cannot start an uninstalled bundle.");
1182 case Bundle.STARTING:
1183 case Bundle.STOPPING:
1184 throw new BundleException("Starting a bundle that is starting or stopping is currently not supported.");
1185 case Bundle.ACTIVE:
1186 return;
1187 case Bundle.INSTALLED:
1188 _resolveBundle(bundle);
Richard S. Halle50da252006-07-25 07:48:06 +00001189 // No break.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001190 case Bundle.RESOLVED:
1191 info.setState(Bundle.STARTING);
Richard S. Halle50da252006-07-25 07:48:06 +00001192 fireBundleEvent(BundleEvent.STARTING, bundle);
1193 break;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001194 }
1195
1196 try
1197 {
Richard S. Hall2a28c8d2006-07-25 07:50:41 +00001198 // Set the bundle's context.
1199 info.setContext(new BundleContextImpl(this, bundle));
1200
Richard S. Hall930fecc2005-08-16 18:33:34 +00001201 // Set the bundle's activator.
Richard S. Halle50da252006-07-25 07:48:06 +00001202 info.setActivator(createBundleActivator(bundle.getInfo()));
Richard S. Hall930fecc2005-08-16 18:33:34 +00001203
1204 // Activate the bundle if it has an activator.
1205 if (bundle.getInfo().getActivator() != null)
1206 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001207 if (System.getSecurityManager() != null)
1208 {
Karl Paulsc19abb42006-07-21 10:23:11 +00001209 java.security.AccessController.doPrivileged(
1210 new PrivilegedActivatorCall(PrivilegedActivatorCall.START,
1211 info.getActivator(), info.getContext()));
Richard S. Hall930fecc2005-08-16 18:33:34 +00001212 }
1213 else
1214 {
1215 info.getActivator().start(info.getContext());
1216 }
1217 }
1218
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001219 // TODO: CONCURRENCY - Reconsider firing event outside of the
1220 // bundle lock.
Richard S. Halle50da252006-07-25 07:48:06 +00001221 info.setState(Bundle.ACTIVE);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001222 fireBundleEvent(BundleEvent.STARTED, bundle);
1223 }
1224 catch (Throwable th)
1225 {
1226 // If there was an error starting the bundle,
1227 // then reset its state to RESOLVED.
1228 info.setState(Bundle.RESOLVED);
1229
Richard S. Hall2a28c8d2006-07-25 07:50:41 +00001230 // Clean up the bundle context.
1231 ((BundleContextImpl) info.getContext()).invalidate();
1232 info.setContext(null);
Richard S. Hall187b87a2006-07-03 09:13:18 +00001233
Richard S. Hall930fecc2005-08-16 18:33:34 +00001234 // Unregister any services offered by this bundle.
1235 m_registry.unregisterServices(bundle);
1236
1237 // Release any services being used by this bundle.
1238 m_registry.ungetServices(bundle);
1239
1240 // Remove any listeners registered by this bundle.
Richard S. Hall92770632006-07-24 10:18:52 +00001241 m_dispatcher.removeListeners(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001242
1243 // The spec says to expect BundleException or
1244 // SecurityException, so rethrow these exceptions.
1245 if (th instanceof BundleException)
1246 {
1247 throw (BundleException) th;
1248 }
1249 else if (th instanceof SecurityException)
1250 {
1251 throw (SecurityException) th;
1252 }
Karl Paulsc19abb42006-07-21 10:23:11 +00001253 else if ((System.getSecurityManager() != null) &&
1254 (th instanceof java.security.PrivilegedActionException))
Richard S. Hall930fecc2005-08-16 18:33:34 +00001255 {
Karl Paulsc19abb42006-07-21 10:23:11 +00001256 th = ((java.security.PrivilegedActionException) th).getException();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001257 }
1258
1259 // Rethrow all other exceptions as a BundleException.
1260 throw new BundleException("Activator start error.", th);
1261 }
1262 }
1263
1264 protected void _resolveBundle(BundleImpl bundle)
1265 throws BundleException
1266 {
1267 // If a security manager is installed, then check for permission
1268 // to import the necessary packages.
1269 if (System.getSecurityManager() != null)
1270 {
1271 URL url = null;
1272 try
1273 {
1274 url = new URL(bundle.getInfo().getLocation());
1275 }
1276 catch (MalformedURLException ex)
1277 {
1278 throw new BundleException("Cannot resolve, bad URL "
1279 + bundle.getInfo().getLocation());
1280 }
Karl Paulsc19abb42006-07-21 10:23:11 +00001281
1282 try
1283 {
1284 java.security.AccessController.doPrivileged(
1285 new CheckImportsPrivileged(url, bundle));
1286 }
1287 catch (java.security.PrivilegedActionException ex)
1288 {
1289 Exception thrown =
1290 ((java.security.PrivilegedActionException) ex).getException();
1291 if (thrown instanceof SecurityException)
1292 {
1293 throw (SecurityException) thrown;
1294 }
1295 else
1296 {
1297 throw new BundleException("Problem resolving: " + ex);
1298 }
1299 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001300 }
1301
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001302 IModule module = bundle.getInfo().getCurrentModule();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001303 try
1304 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001305 m_policyCore.resolve(module);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001306 }
1307 catch (ResolveException ex)
1308 {
1309 if (ex.getModule() != null)
1310 {
1311 throw new BundleException(
1312 "Unresolved package in bundle "
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001313 + Util.getBundleIdFromModuleId(ex.getModule().getId())
Richard S. Hall930fecc2005-08-16 18:33:34 +00001314 + ": " + ex.getPackage());
1315 }
1316 else
1317 {
1318 throw new BundleException(ex.getMessage());
1319 }
1320 }
1321
1322 bundle.getInfo().setState(Bundle.RESOLVED);
1323 }
1324
1325 protected void updateBundle(BundleImpl bundle, InputStream is)
1326 throws BundleException
1327 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001328 // Acquire bundle lock.
1329 acquireBundleLock(bundle);
1330
1331 try
1332 {
1333 _updateBundle(bundle, is);
1334 }
1335 finally
1336 {
1337 // Release bundle lock.
1338 releaseBundleLock(bundle);
1339 }
1340 }
1341
1342 protected void _updateBundle(BundleImpl bundle, InputStream is)
1343 throws BundleException
1344 {
1345 // We guarantee to close the input stream, so put it in a
1346 // finally clause.
1347
1348 try
1349 {
1350 // Variable to indicate whether bundle is active or not.
1351 Exception rethrow = null;
1352
1353 // Cannot update an uninstalled bundle.
1354 BundleInfo info = bundle.getInfo();
1355 if (info.getState() == Bundle.UNINSTALLED)
1356 {
1357 throw new IllegalStateException("The bundle is uninstalled.");
1358 }
1359
1360 // First get the update-URL from our header.
1361 String updateLocation = (String)
1362 info.getCurrentHeader().get(Constants.BUNDLE_UPDATELOCATION);
1363
1364 // If no update location specified, use original location.
1365 if (updateLocation == null)
1366 {
1367 updateLocation = info.getLocation();
1368 }
1369
1370 // Stop the bundle, but do not change the persistent state.
1371 stopBundle(bundle, false);
1372
1373 try
1374 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001375 // Get the bundle's archive.
Richard S. Hall04bdbb12006-03-15 14:26:15 +00001376 BundleArchive archive = m_cache.getArchive(info.getBundleId());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001377 // Update the bundle; this operation will increase
1378 // the revision count for the bundle.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001379 archive.revise(updateLocation, is);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001380 // Create a module for the new revision; the revision is
1381 // base zero, so subtract one from the revision count to
1382 // get the revision of the new update.
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001383 try
1384 {
1385 IModule module = createModule(
1386 info.getBundleId(),
1387 archive.getRevisionCount() - 1,
1388 info.getCurrentHeader());
Karl Paulsc19abb42006-07-21 10:23:11 +00001389
1390 Object sm = System.getSecurityManager();
1391
1392 if (sm != null)
1393 {
1394 ((SecurityManager) sm).checkPermission(
1395 new AdminPermission(bundle, AdminPermission.LIFECYCLE));
1396 }
1397
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001398 // Add module to bundle info.
1399 info.addModule(module);
1400 }
1401 catch (Exception ex)
1402 {
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001403 try
1404 {
1405 archive.undoRevise();
1406 }
1407 catch (Exception busted)
1408 {
1409 m_logger.log(Logger.LOG_ERROR, "Unable to rollback.", busted);
1410 }
1411
Karl Pauls3390b4a2006-07-19 13:20:32 +00001412 throw ex;
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001413 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001414 }
1415 catch (Exception ex)
1416 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001417 m_logger.log(Logger.LOG_ERROR, "Unable to update the bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001418 rethrow = ex;
1419 }
1420
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001421 // Set new state, mark as needing a refresh, and fire updated event
1422 // if successful.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001423 if (rethrow == null)
1424 {
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001425 info.setState(Bundle.INSTALLED);
1426 info.setLastModified(System.currentTimeMillis());
1427
Richard S. Hall60c26d42006-07-19 10:35:04 +00001428 // Mark previous the bundle's old module for removal since
1429 // it can no longer be used to resolve other modules per the spec.
Richard S. Hall594145f2006-07-23 13:07:18 +00001430 ((ModuleImpl) info.getModules()[info.getModules().length - 2])
1431 .setRemovalPending(true);
Richard S. Hall60c26d42006-07-19 10:35:04 +00001432
Richard S. Hall930fecc2005-08-16 18:33:34 +00001433 fireBundleEvent(BundleEvent.UPDATED, bundle);
1434 }
1435
1436 // Restart bundle, but do not change the persistent state.
1437 // This will not start the bundle if it was not previously
1438 // active.
1439 startBundle(bundle, false);
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001440
Richard S. Hall930fecc2005-08-16 18:33:34 +00001441 // If update failed, rethrow exception.
1442 if (rethrow != null)
1443 {
Karl Paulsc19abb42006-07-21 10:23:11 +00001444 if ((System.getSecurityManager() != null) &&
1445 (rethrow instanceof SecurityException))
1446 {
1447 throw (SecurityException) rethrow;
1448 }
1449
Richard S. Hall930fecc2005-08-16 18:33:34 +00001450 throw new BundleException("Update failed.", rethrow);
1451 }
1452 }
1453 finally
1454 {
1455 try
1456 {
1457 if (is != null) is.close();
1458 }
1459 catch (IOException ex)
1460 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001461 m_logger.log(Logger.LOG_ERROR, "Unable to close input stream.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001462 }
1463 }
1464 }
1465
1466 protected void stopBundle(BundleImpl bundle, boolean record)
1467 throws BundleException
1468 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001469 // Acquire bundle lock.
1470 acquireBundleLock(bundle);
1471
1472 try
1473 {
1474 _stopBundle(bundle, record);
1475 }
1476 finally
1477 {
1478 // Always release bundle lock.
1479 releaseBundleLock(bundle);
1480 }
1481 }
1482
1483 private void _stopBundle(BundleImpl bundle, boolean record)
1484 throws BundleException
1485 {
1486 Throwable rethrow = null;
1487
1488 // Set the bundle's persistent state to inactive if necessary.
1489 if (record)
1490 {
1491 bundle.getInfo().setPersistentStateInactive();
1492 }
1493
1494 BundleInfo info = bundle.getInfo();
1495
1496 switch (info.getState())
1497 {
1498 case Bundle.UNINSTALLED:
1499 throw new IllegalStateException("Cannot stop an uninstalled bundle.");
1500 case Bundle.STARTING:
1501 case Bundle.STOPPING:
1502 throw new BundleException("Stopping a bundle that is starting or stopping is currently not supported.");
1503 case Bundle.INSTALLED:
1504 case Bundle.RESOLVED:
1505 return;
1506 case Bundle.ACTIVE:
1507 // Set bundle state..
1508 info.setState(Bundle.STOPPING);
Richard S. Halle50da252006-07-25 07:48:06 +00001509 fireBundleEvent(BundleEvent.STOPPING, bundle);
1510 break;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001511 }
Richard S. Halle50da252006-07-25 07:48:06 +00001512
Richard S. Hall930fecc2005-08-16 18:33:34 +00001513 try
1514 {
1515 if (bundle.getInfo().getActivator() != null)
1516 {
1517 if (System.getSecurityManager() != null)
1518 {
Karl Paulsc19abb42006-07-21 10:23:11 +00001519 java.security.AccessController.doPrivileged(
1520 new PrivilegedActivatorCall(PrivilegedActivatorCall.STOP,
1521 info.getActivator(), info.getContext()));
Richard S. Hall930fecc2005-08-16 18:33:34 +00001522 }
1523 else
1524 {
1525 info.getActivator().stop(info.getContext());
1526 }
1527 }
1528
1529 // Try to save the activator in the cache.
1530 // NOTE: This is non-standard OSGi behavior and only
1531 // occurs if strictness is disabled.
1532 String strict = m_config.get(FelixConstants.STRICT_OSGI_PROP);
1533 boolean isStrict = (strict == null) ? true : strict.equals("true");
1534 if (!isStrict)
1535 {
1536 try
1537 {
1538 m_cache.getArchive(info.getBundleId())
1539 .setActivator(info.getActivator());
1540 }
1541 catch (Exception ex)
1542 {
1543 // Problem saving activator, so ignore it.
1544 // TODO: Perhaps we should handle this some other way?
1545 }
1546 }
1547 }
1548 catch (Throwable th)
1549 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001550 m_logger.log(Logger.LOG_ERROR, "Error stopping bundle.", th);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001551 rethrow = th;
1552 }
Richard S. Hall2a28c8d2006-07-25 07:50:41 +00001553
1554 // Clean up the bundle context.
1555 ((BundleContextImpl) info.getContext()).invalidate();
1556 info.setContext(null);
Richard S. Hall187b87a2006-07-03 09:13:18 +00001557
Richard S. Hall930fecc2005-08-16 18:33:34 +00001558 // Unregister any services offered by this bundle.
1559 m_registry.unregisterServices(bundle);
1560
1561 // Release any services being used by this bundle.
1562 m_registry.ungetServices(bundle);
1563
1564 // The spec says that we must remove all event
1565 // listeners for a bundle when it is stopped.
Richard S. Hall92770632006-07-24 10:18:52 +00001566 m_dispatcher.removeListeners(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001567
1568 info.setState(Bundle.RESOLVED);
1569 fireBundleEvent(BundleEvent.STOPPED, bundle);
1570
1571 // Throw activator error if there was one.
1572 if (rethrow != null)
1573 {
1574 // The spec says to expect BundleException or
1575 // SecurityException, so rethrow these exceptions.
1576 if (rethrow instanceof BundleException)
1577 {
1578 throw (BundleException) rethrow;
1579 }
1580 else if (rethrow instanceof SecurityException)
1581 {
1582 throw (SecurityException) rethrow;
1583 }
Karl Paulsc19abb42006-07-21 10:23:11 +00001584 else if ((System.getSecurityManager() != null) &&
1585 (rethrow instanceof java.security.PrivilegedActionException))
Richard S. Hall930fecc2005-08-16 18:33:34 +00001586 {
Karl Paulsc19abb42006-07-21 10:23:11 +00001587 rethrow = ((java.security.PrivilegedActionException) rethrow).getException();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001588 }
1589
1590 // Rethrow all other exceptions as a BundleException.
1591 throw new BundleException("Activator stop error.", rethrow);
1592 }
1593 }
1594
1595 protected void uninstallBundle(BundleImpl bundle) throws BundleException
1596 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001597 // Acquire bundle lock.
1598 acquireBundleLock(bundle);
1599
1600 try
1601 {
1602 _uninstallBundle(bundle);
1603 }
1604 finally
1605 {
1606 // Always release bundle lock.
1607 releaseBundleLock(bundle);
1608 }
1609 }
1610
1611 private void _uninstallBundle(BundleImpl bundle) throws BundleException
1612 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001613 BundleInfo info = bundle.getInfo();
1614 if (info.getState() == Bundle.UNINSTALLED)
1615 {
1616 throw new IllegalStateException("The bundle is uninstalled.");
1617 }
1618
1619 // The spec says that uninstall should always succeed, so
1620 // catch an exception here if stop() doesn't succeed and
1621 // rethrow it at the end.
1622 try
1623 {
1624 stopBundle(bundle, true);
1625 }
1626 catch (BundleException ex)
1627 {
Richard S. Hall447c52f2006-07-04 09:25:07 +00001628 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001629 }
1630
1631 // Remove the bundle from the installed map.
1632 BundleImpl target = null;
1633 synchronized (m_installedBundleLock_Priority2)
1634 {
1635 target = (BundleImpl) m_installedBundleMap.remove(info.getLocation());
1636 }
1637
1638 // Finally, put the uninstalled bundle into the
1639 // uninstalled list for subsequent refreshing.
1640 if (target != null)
1641 {
1642 // Set the bundle's persistent state to uninstalled.
1643 target.getInfo().setPersistentStateUninstalled();
1644
Richard S. Hall60c26d42006-07-19 10:35:04 +00001645 // Mark current module for removal since it can no longer
1646 // be used to resolve other modules per the spec.
Richard S. Hall594145f2006-07-23 13:07:18 +00001647 ((ModuleImpl) target.getInfo().getCurrentModule()).setRemovalPending(true);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001648
1649 // Put bundle in uninstalled bundle array.
1650 rememberUninstalledBundle(bundle);
1651 }
1652 else
1653 {
1654 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001655 Logger.LOG_ERROR, "Unable to remove bundle from installed map!");
Richard S. Hall930fecc2005-08-16 18:33:34 +00001656 }
1657
1658 // Set state to uninstalled.
1659 info.setState(Bundle.UNINSTALLED);
Richard S. Hall69d84792006-01-13 13:55:13 +00001660 info.setLastModified(System.currentTimeMillis());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001661
1662 // Fire bundle event.
1663 fireBundleEvent(BundleEvent.UNINSTALLED, bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001664 }
1665
1666 //
1667 // Implementation of BundleContext interface methods.
1668 //
1669
1670 /**
1671 * Implementation for BundleContext.getProperty(). Returns
1672 * environment property associated with the framework.
1673 *
1674 * @param key The name of the property to retrieve.
1675 * @return The value of the specified property or null.
1676 **/
1677 protected String getProperty(String key)
1678 {
1679 // First, check the config properties.
Richard S. Hallea415752005-12-05 19:30:28 +00001680 String val = (String) m_config.get(key);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001681 // If not found, then try the system properties.
1682 return (val == null) ? System.getProperty(key) : val;
1683 }
1684
1685 protected Bundle installBundle(String location, InputStream is)
1686 throws BundleException
1687 {
1688 return installBundle(-1, location, is);
1689 }
1690
1691 private Bundle installBundle(long id, String location, InputStream is)
1692 throws BundleException
1693 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001694 BundleImpl bundle = null;
1695
1696 // Acquire an install lock.
1697 acquireInstallLock(location);
1698
1699 try
1700 {
1701 // Check to see if the framework is still running;
1702 if ((getStatus() == Felix.STOPPING_STATUS) ||
1703 (getStatus() == Felix.INITIAL_STATUS))
1704 {
1705 throw new BundleException("The framework has been shutdown.");
1706 }
1707
1708 // If bundle location is already installed, then
1709 // return it as required by the OSGi specification.
1710 bundle = (BundleImpl) getBundle(location);
1711 if (bundle != null)
1712 {
1713 return bundle;
1714 }
1715
1716 // Determine if this is a new or existing bundle.
1717 boolean isNew = (id < 0);
1718
1719 // If the bundle is new we must cache its JAR file.
1720 if (isNew)
1721 {
1722 // First generate an identifier for it.
1723 id = getNextId();
1724
1725 try
1726 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001727 // Add the bundle to the cache.
Richard S. Hall9a3e9852006-03-04 03:44:05 +00001728 m_cache.create(id, location, is);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001729 }
1730 catch (Exception ex)
1731 {
1732 throw new BundleException(
1733 "Unable to cache bundle: " + location, ex);
1734 }
1735 finally
1736 {
1737 try
1738 {
1739 if (is != null) is.close();
1740 }
1741 catch (IOException ex)
1742 {
1743 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001744 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001745 "Unable to close input stream.", ex);
1746 }
1747 }
1748 }
1749 else
1750 {
1751 // If the bundle we are installing is not new,
1752 // then try to purge old revisions before installing
1753 // it; this is done just in case a "refresh"
1754 // didn't occur last session...this would only be
1755 // due to an error or system crash.
1756 try
1757 {
1758 if (m_cache.getArchive(id).getRevisionCount() > 1)
1759 {
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001760 m_cache.getArchive(id).purge();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001761 }
1762 }
1763 catch (Exception ex)
1764 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001765 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001766 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001767 "Could not purge bundle.", ex);
1768 }
1769 }
1770
1771 try
1772 {
Richard S. Hall04bdbb12006-03-15 14:26:15 +00001773 BundleArchive archive = m_cache.getArchive(id);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001774 bundle = new BundleImpl(this, createBundleInfo(archive));
Karl Paulsc19abb42006-07-21 10:23:11 +00001775
1776 Object sm = System.getSecurityManager();
1777
1778 if (sm != null)
1779 {
1780 ((SecurityManager) sm).checkPermission(
1781 new AdminPermission(bundle, AdminPermission.LIFECYCLE));
1782 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001783 }
1784 catch (Exception ex)
1785 {
1786 // If the bundle is new, then remove it from the cache.
1787 // TODO: Perhaps it should be removed if it is not new too.
1788 if (isNew)
1789 {
1790 try
1791 {
1792 m_cache.remove(m_cache.getArchive(id));
1793 }
1794 catch (Exception ex1)
1795 {
1796 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001797 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001798 "Could not remove from cache.", ex1);
1799 }
1800 }
Karl Paulsc19abb42006-07-21 10:23:11 +00001801
1802 if ((System.getSecurityManager() != null) &&
1803 (ex instanceof SecurityException))
1804 {
1805 throw (SecurityException) ex;
1806 }
1807
Richard S. Hall930fecc2005-08-16 18:33:34 +00001808 throw new BundleException("Could not create bundle object.", ex);
1809 }
1810
1811 // If the bundle is new, then set its start level; existing
1812 // bundles already have their start level set.
1813 if (isNew)
1814 {
1815 // This will persistently set the bundle's start level.
1816 bundle.getInfo().setStartLevel(getInitialBundleStartLevel());
Richard S. Hall69d84792006-01-13 13:55:13 +00001817 bundle.getInfo().setLastModified(System.currentTimeMillis());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001818 }
1819
1820 synchronized (m_installedBundleLock_Priority2)
1821 {
1822 m_installedBundleMap.put(location, bundle);
1823 }
1824 }
1825 finally
1826 {
1827 // Always release install lock.
1828 releaseInstallLock(location);
1829
1830 // Always try to close the input stream.
1831 try
1832 {
1833 if (is != null) is.close();
1834 }
1835 catch (IOException ex)
1836 {
1837 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001838 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001839 "Unable to close input stream.", ex);
1840 // Not much else we can do.
1841 }
1842 }
1843
1844 // Fire bundle event.
1845 fireBundleEvent(BundleEvent.INSTALLED, bundle);
1846
1847 // Return new bundle.
1848 return bundle;
1849 }
1850
1851 /**
1852 * Retrieves a bundle from its location.
1853 *
1854 * @param location The location of the bundle to retrieve.
1855 * @return The bundle associated with the location or null if there
1856 * is no bundle associated with the location.
1857 **/
1858 protected Bundle getBundle(String location)
1859 {
1860 synchronized (m_installedBundleLock_Priority2)
1861 {
1862 return (Bundle) m_installedBundleMap.get(location);
1863 }
1864 }
1865
1866 /**
1867 * Implementation for BundleContext.getBundle(). Retrieves a
1868 * bundle from its identifier.
1869 *
1870 * @param id The identifier of the bundle to retrieve.
1871 * @return The bundle associated with the identifier or null if there
1872 * is no bundle associated with the identifier.
1873 **/
1874 protected Bundle getBundle(long id)
1875 {
1876 synchronized (m_installedBundleLock_Priority2)
1877 {
1878 BundleImpl bundle = null;
1879
1880 for (Iterator i = m_installedBundleMap.values().iterator(); i.hasNext(); )
1881 {
1882 bundle = (BundleImpl) i.next();
1883 if (bundle.getInfo().getBundleId() == id)
1884 {
1885 return bundle;
1886 }
1887 }
1888 }
1889
Richard S. Halla6443462006-06-29 15:16:05 +00001890 synchronized (m_uninstalledBundlesLock_Priority3)
1891 {
Richard S. Hall5a1baf02006-07-20 08:02:42 +00001892 for (int i = 0;
1893 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
1894 i++)
Richard S. Halla6443462006-06-29 15:16:05 +00001895 {
1896 if (m_uninstalledBundles[i].getInfo().getBundleId() == id)
1897 {
1898 return m_uninstalledBundles[i];
1899 }
1900 }
1901 }
1902
Richard S. Hall930fecc2005-08-16 18:33:34 +00001903 return null;
1904 }
1905
1906 // Private member for method below.
1907 private Comparator m_comparator = null;
1908
1909 /**
1910 * Implementation for BundleContext.getBundles(). Retrieves
1911 * all installed bundles.
1912 *
1913 * @return An array containing all installed bundles or null if
1914 * there are no installed bundles.
1915 **/
1916 protected Bundle[] getBundles()
1917 {
1918 if (m_comparator == null)
1919 {
1920 m_comparator = new Comparator() {
1921 public int compare(Object o1, Object o2)
1922 {
1923 Bundle b1 = (Bundle) o1;
1924 Bundle b2 = (Bundle) o2;
1925 if (b1.getBundleId() > b2.getBundleId())
1926 return 1;
1927 else if (b1.getBundleId() < b2.getBundleId())
1928 return -1;
1929 return 0;
1930 }
1931 };
1932 }
1933
1934 Bundle[] bundles = null;
1935
1936 synchronized (m_installedBundleLock_Priority2)
1937 {
1938 if (m_installedBundleMap.size() == 0)
1939 {
1940 return null;
1941 }
1942
1943 bundles = new Bundle[m_installedBundleMap.size()];
1944 int counter = 0;
1945 for (Iterator i = m_installedBundleMap.values().iterator(); i.hasNext(); )
1946 {
1947 bundles[counter++] = (Bundle) i.next();
1948 }
1949 }
1950
1951 Arrays.sort(bundles, m_comparator);
1952
1953 return bundles;
1954 }
1955
1956 protected void addBundleListener(Bundle bundle, BundleListener l)
1957 {
Richard S. Hall92770632006-07-24 10:18:52 +00001958 m_dispatcher.addListener(bundle, BundleListener.class, l, null);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001959 }
1960
Karl Pauls3390b4a2006-07-19 13:20:32 +00001961 protected void removeBundleListener(Bundle bundle, BundleListener l)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001962 {
Richard S. Hall92770632006-07-24 10:18:52 +00001963 m_dispatcher.removeListener(bundle, BundleListener.class, l);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001964 }
1965
1966 /**
1967 * Implementation for BundleContext.addServiceListener().
1968 * Adds service listener to the listener list so that is
1969 * can listen for <code>ServiceEvent</code>s.
1970 *
1971 * @param bundle The bundle that registered the listener.
1972 * @param l The service listener to add to the listener list.
1973 * @param f The filter for the listener; may be null.
1974 **/
1975 protected void addServiceListener(Bundle bundle, ServiceListener l, String f)
1976 throws InvalidSyntaxException
1977 {
Richard S. Hall92770632006-07-24 10:18:52 +00001978 m_dispatcher.addListener(
1979 bundle, ServiceListener.class, l, (f == null) ? null : new FilterImpl(m_logger, f));
Richard S. Hall930fecc2005-08-16 18:33:34 +00001980 }
1981
1982 /**
1983 * Implementation for BundleContext.removeServiceListener().
1984 * Removes service listeners from the listener list.
Karl Pauls3390b4a2006-07-19 13:20:32 +00001985 *
1986 * @param bundle The context bundle of the listener
Richard S. Hall930fecc2005-08-16 18:33:34 +00001987 * @param l The service listener to remove from the listener list.
1988 **/
Karl Pauls3390b4a2006-07-19 13:20:32 +00001989 protected void removeServiceListener(Bundle bundle, ServiceListener l)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001990 {
Richard S. Hall92770632006-07-24 10:18:52 +00001991 m_dispatcher.removeListener(bundle, ServiceListener.class, l);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001992 }
1993
1994 protected void addFrameworkListener(Bundle bundle, FrameworkListener l)
1995 {
Richard S. Hall92770632006-07-24 10:18:52 +00001996 m_dispatcher.addListener(bundle, FrameworkListener.class, l, null);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001997 }
1998
Karl Pauls3390b4a2006-07-19 13:20:32 +00001999 protected void removeFrameworkListener(Bundle bundle, FrameworkListener l)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002000 {
Richard S. Hall92770632006-07-24 10:18:52 +00002001 m_dispatcher.removeListener(bundle, FrameworkListener.class, l);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002002 }
2003
2004 /**
2005 * Implementation for BundleContext.registerService(). Registers
2006 * a service for the specified bundle bundle.
2007 *
2008 * @param classNames A string array containing the names of the classes
2009 * under which the new service is available.
2010 * @param svcObj The service object or <code>ServiceFactory</code>.
2011 * @param dict A dictionary of properties that further describe the
2012 * service or null.
2013 * @return A <code>ServiceRegistration</code> object or null.
2014 **/
2015 protected ServiceRegistration registerService(
2016 BundleImpl bundle, String[] classNames, Object svcObj, Dictionary dict)
2017 {
2018 if (classNames == null)
2019 {
2020 throw new NullPointerException("Service class names cannot be null.");
2021 }
2022 else if (svcObj == null)
2023 {
2024 throw new IllegalArgumentException("Service object cannot be null.");
2025 }
2026
Richard S. Hall930fecc2005-08-16 18:33:34 +00002027 // Acquire bundle lock.
Richard S. Hall3c26cc02006-02-17 13:51:21 +00002028 acquireBundleLock(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002029
2030 ServiceRegistration reg = null;
2031
2032 try
2033 {
2034 BundleInfo info = bundle.getInfo();
2035
2036 // Can only register services if starting or active.
2037 if ((info.getState() & (Bundle.STARTING | Bundle.ACTIVE)) == 0)
2038 {
2039 throw new IllegalStateException(
2040 "Can only register services while bundle is active or activating.");
2041 }
2042
2043 // Check to make sure that the service object is
2044 // an instance of all service classes; ignore if
2045 // service object is a service factory.
2046 if (!(svcObj instanceof ServiceFactory))
2047 {
2048 for (int i = 0; i < classNames.length; i++)
2049 {
Richard S. Hallbc549622006-07-13 13:33:22 +00002050 Class clazz = Util.loadClassUsingClass(svcObj.getClass(), classNames[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002051 if (clazz == null)
2052 {
2053 throw new IllegalArgumentException(
2054 "Cannot cast service: " + classNames[i]);
2055 }
2056 else if (!clazz.isAssignableFrom(svcObj.getClass()))
2057 {
2058 throw new IllegalArgumentException(
2059 "Service object is not an instance of \""
2060 + classNames[i] + "\".");
2061 }
2062 }
2063 }
2064
2065 reg = m_registry.registerService(bundle, classNames, svcObj, dict);
2066 }
2067 finally
2068 {
2069 // Always release bundle lock.
2070 releaseBundleLock(bundle);
2071 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +00002072
2073 // TODO: CONCURRENCY - Reconsider firing event here, outside of the
2074 // bundle lock.
2075
Richard S. Hall930fecc2005-08-16 18:33:34 +00002076 // NOTE: The service registered event is fired from the service
2077 // registry to the framework, where it is then redistributed to
2078 // interested service event listeners.
2079
2080 return reg;
2081 }
2082
Richard S. Hall930fecc2005-08-16 18:33:34 +00002083 protected ServiceReference[] getServiceReferences(
2084 BundleImpl bundle, String className, String expr)
2085 throws InvalidSyntaxException
2086 {
2087 // Define filter if expression is not null.
2088 Filter filter = null;
2089 if (expr != null)
2090 {
2091 filter = new FilterImpl(m_logger, expr);
2092 }
2093
2094 // Ask the service registry for all matching service references.
2095 List refList = m_registry.getServiceReferences(className, filter);
2096
2097 // The returned reference list must be filtered for two cases:
2098 // 1) The requesting bundle may not be wired to the same class
2099 // as the providing bundle (i.e, different versions), so filter
2100 // any services for which the requesting bundle might get a
2101 // class cast exception.
2102 // 2) Security is enabled and the requesting bundle does not have
2103 // permission access the service.
2104 for (int refIdx = 0; (refList != null) && (refIdx < refList.size()); refIdx++)
2105 {
2106 // Get the current service reference.
2107 ServiceReference ref = (ServiceReference) refList.get(refIdx);
2108
Richard S. Hall930fecc2005-08-16 18:33:34 +00002109 // Now check for castability.
Richard S. Hall92770632006-07-24 10:18:52 +00002110 if (!Felix.isServiceAssignable(bundle, ref))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002111 {
2112 refList.remove(refIdx);
2113 refIdx--;
2114 }
2115 }
2116
2117 if (refList.size() > 0)
2118 {
2119 return (ServiceReference[]) refList.toArray(new ServiceReference[refList.size()]);
2120 }
2121
2122 return null;
2123 }
2124
2125 /**
2126 * This method determines if the requesting bundle is able to cast
2127 * the specified service reference based on class visibility rules
2128 * of the underlying modules.
2129 * @param requester The bundle requesting the service.
2130 * @param ref The service in question.
2131 * @return <tt>true</tt> if the requesting bundle is able to case
2132 * the service object to a known type.
2133 **/
Richard S. Hall92770632006-07-24 10:18:52 +00002134 public static boolean isServiceAssignable(Bundle requester, ServiceReference ref)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002135 {
2136 // Boolean flag.
2137 boolean allow = true;
2138 // Get the service's objectClass property.
2139 String[] objectClass = (String[]) ref.getProperty(FelixConstants.OBJECTCLASS);
2140
2141 // The the service reference is not assignable when the requesting
2142 // bundle is wired to a different version of the service object.
2143 // NOTE: We are pessimistic here, if any class in the service's
2144 // objectClass is not usable by the requesting bundle, then we
2145 // disallow the service reference.
2146 for (int classIdx = 0; (allow) && (classIdx < objectClass.length); classIdx++)
2147 {
2148 if (!ref.isAssignableTo(requester, objectClass[classIdx]))
2149 {
2150 allow = false;
2151 }
2152 }
2153 return allow;
2154 }
2155
2156 protected Object getService(Bundle bundle, ServiceReference ref)
2157 {
2158 // Check that the bundle has permission to get at least
2159 // one of the service interfaces; the objectClass property
2160 // of the service stores its service interfaces.
2161 String[] objectClass = (String[])
2162 ref.getProperty(Constants.OBJECTCLASS);
2163 if (objectClass == null)
2164 {
2165 return null;
2166 }
2167
Richard S. Hall930fecc2005-08-16 18:33:34 +00002168 return m_registry.getService(bundle, ref);
2169 }
2170
2171 protected boolean ungetService(Bundle bundle, ServiceReference ref)
2172 {
2173 return m_registry.ungetService(bundle, ref);
2174 }
2175
2176 protected File getDataFile(BundleImpl bundle, String s)
2177 {
2178 // The spec says to throw an error if the bundle
2179 // is stopped, which I assume means not active,
2180 // starting, or stopping.
2181 if ((bundle.getInfo().getState() != Bundle.ACTIVE) &&
2182 (bundle.getInfo().getState() != Bundle.STARTING) &&
2183 (bundle.getInfo().getState() != Bundle.STOPPING))
2184 {
2185 throw new IllegalStateException("Only active bundles can create files.");
2186 }
2187 try
2188 {
2189 return m_cache.getArchive(
2190 bundle.getInfo().getBundleId()).getDataFile(s);
2191 }
2192 catch (Exception ex)
2193 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002194 m_logger.log(Logger.LOG_ERROR, ex.getMessage());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002195 return null;
2196 }
2197 }
2198
2199 //
2200 // PackageAdmin related methods.
2201 //
2202
2203 /**
Richard S. Hallc87d41a2006-07-03 07:57:28 +00002204 * This method returns the bundle associated with the specified class if
2205 * the class was loaded from a bundle from this framework instance. If the
2206 * class was not loaded from a bundle or was loaded by a bundle in another
2207 * framework instance, then <tt>null</tt> is returned.
2208 *
2209 * @param clazz the class for which to find its associated bundle.
2210 * @return the bundle associated with the specified class or <tt>null</tt>
2211 * if the class was not loaded by a bundle or its associated
2212 * bundle belongs to a different framework instance.
2213 **/
2214 protected Bundle getBundle(Class clazz)
2215 {
2216 if (clazz.getClassLoader() instanceof ContentClassLoader)
2217 {
2218 IContentLoader contentLoader =
2219 ((ContentClassLoader) clazz.getClassLoader()).getContentLoader();
2220 IModule[] modules = m_factory.getModules();
2221 for (int i = 0; i < modules.length; i++)
2222 {
2223 if (modules[i].getContentLoader() == contentLoader)
2224 {
2225 long id = Util.getBundleIdFromModuleId(modules[i].getId());
2226 return getBundle(id);
2227 }
2228 }
2229 }
2230 return null;
2231 }
2232
2233 /**
Richard S. Hall1bdc3722006-07-03 09:52:07 +00002234 * Returns the exported packages associated with the specified
Richard S. Hallafc52d42006-02-09 13:04:32 +00002235 * package name. This is used by the PackageAdmin service
2236 * implementation.
2237 *
2238 * @param name The name of the exported package to find.
2239 * @return The exported package or null if no matching package was found.
2240 **/
2241 protected ExportedPackage[] getExportedPackages(String name)
2242 {
2243 // First, get all exporters of the package.
2244 ExportedPackage[] pkgs = null;
Richard S. Hallefb3a232006-07-20 16:03:00 +00002245 IModule[] exporters = m_policyCore.getInUseExporters(new R4Import(name, null, null), true);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002246 if (exporters != null)
2247 {
Richard S. Hall88e0ae62006-02-09 13:22:21 +00002248 pkgs = new ExportedPackage[exporters.length];
Richard S. Hallafc52d42006-02-09 13:04:32 +00002249 for (int pkgIdx = 0; pkgIdx < pkgs.length; pkgIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002250 {
Richard S. Hallafc52d42006-02-09 13:04:32 +00002251 // Get the bundle associated with the current exporting module.
2252 BundleImpl bundle = (BundleImpl) getBundle(
2253 Util.getBundleIdFromModuleId(exporters[pkgIdx].getId()));
2254
2255 // We need to find the version of the exported package, but this
2256 // is tricky since there may be multiple versions of the package
2257 // offered by a given bundle, since multiple revisions of the
2258 // bundle JAR file may exist if the bundle was updated without
2259 // refreshing the framework. In this case, each revision of the
2260 // bundle JAR file is represented as a module in the BundleInfo
2261 // module array, which is ordered from oldest to newest. We assume
2262 // that the first module found to be exporting the package is the
2263 // provider of the package, which makes sense since it must have
2264 // been resolved first.
2265 IModule[] modules = bundle.getInfo().getModules();
2266 for (int modIdx = 0; modIdx < modules.length; modIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002267 {
Richard S. Hallafc52d42006-02-09 13:04:32 +00002268 R4Export export = Util.getExportPackage(modules[modIdx], name);
2269 if (export != null)
2270 {
2271 pkgs[pkgIdx] =
2272 new ExportedPackageImpl(
Richard S. Hall60c26d42006-07-19 10:35:04 +00002273 this, bundle, modules[modIdx], export);
Richard S. Hallafc52d42006-02-09 13:04:32 +00002274 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002275 }
2276 }
2277 }
2278
Richard S. Hallafc52d42006-02-09 13:04:32 +00002279 return pkgs;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002280 }
2281
2282 /**
2283 * Returns an array of all actively exported packages from the specified
2284 * bundle or if the specified bundle is <tt>null</tt> an array
2285 * containing all actively exported packages by all bundles.
2286 *
2287 * @param b The bundle whose exported packages are to be retrieved
2288 * or <tt>null</tt> if the exported packages of all bundles are
2289 * to be retrieved.
2290 * @return An array of exported packages.
2291 **/
2292 protected ExportedPackage[] getExportedPackages(Bundle b)
2293 {
2294 List list = new ArrayList();
2295
2296 // If a bundle is specified, then return its
2297 // exported packages.
2298 if (b != null)
2299 {
2300 BundleImpl bundle = (BundleImpl) b;
2301 getExportedPackages(bundle, list);
2302 }
2303 // Otherwise return all exported packages.
2304 else
2305 {
2306 // To create a list of all exported packages, we must look
2307 // in the installed and uninstalled sets of bundles. To
2308 // ensure a somewhat consistent view, we will gather all
2309 // of this information from within the installed bundle
2310 // lock.
2311 synchronized (m_installedBundleLock_Priority2)
2312 {
2313 // First get exported packages from uninstalled bundles.
2314 synchronized (m_uninstalledBundlesLock_Priority3)
2315 {
2316 for (int bundleIdx = 0;
2317 (m_uninstalledBundles != null) && (bundleIdx < m_uninstalledBundles.length);
2318 bundleIdx++)
2319 {
2320 BundleImpl bundle = m_uninstalledBundles[bundleIdx];
2321 getExportedPackages(bundle, list);
2322 }
2323 }
2324
2325 // Now get exported packages from installed bundles.
2326 Bundle[] bundles = getBundles();
2327 for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
2328 {
2329 BundleImpl bundle = (BundleImpl) bundles[bundleIdx];
2330 getExportedPackages(bundle, list);
2331 }
2332 }
2333 }
2334
2335 return (ExportedPackage[]) list.toArray(new ExportedPackage[list.size()]);
2336 }
2337
2338 /**
2339 * Adds any current active exported packages from the specified bundle
2340 * to the passed in list.
2341 * @param bundle The bundle from which to retrieve exported packages.
2342 * @param list The list to which the exported packages are added
2343 **/
2344 private void getExportedPackages(BundleImpl bundle, List list)
2345 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002346 // Since a bundle may have many modules associated with it,
2347 // one for each revision in the cache, search each module
2348 // for each revision to get all exports.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002349 IModule[] modules = bundle.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002350 for (int modIdx = 0; modIdx < modules.length; modIdx++)
2351 {
Richard S. Hall594145f2006-07-23 13:07:18 +00002352 R4Export[] exports = modules[modIdx].getDefinition().getExports();
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002353 if ((exports != null) && (exports.length > 0))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002354 {
2355 for (int expIdx = 0; expIdx < exports.length; expIdx++)
2356 {
2357 // See if the target bundle's module is one of the
2358 // "in use" exporters of the package.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002359 IModule[] inUseModules =
2360 m_policyCore.getInUseExporters(
Richard S. Hallefb3a232006-07-20 16:03:00 +00002361 new R4Import(exports[expIdx].getName(), null, null), true);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002362 // Search through the current providers to find the target
2363 // module.
2364 for (int i = 0; (inUseModules != null) && (i < inUseModules.length); i++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002365 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002366 if (inUseModules[i] == modules[modIdx])
2367 {
2368 list.add(new ExportedPackageImpl(
Richard S. Hall60c26d42006-07-19 10:35:04 +00002369 this, bundle, modules[modIdx], exports[expIdx]));
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002370 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002371 }
2372 }
2373 }
2374 }
2375 }
2376
2377 protected Bundle[] getImportingBundles(ExportedPackage ep)
2378 {
Richard S. Halle1f53a52006-07-17 11:06:59 +00002379 // Get exporting bundle.
Richard S. Hall930fecc2005-08-16 18:33:34 +00002380 BundleImpl exporter = (BundleImpl)
Richard S. Halle1f53a52006-07-17 11:06:59 +00002381 ((ExportedPackage) ep).getExportingBundle();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002382 BundleInfo exporterInfo = exporter.getInfo();
2383
2384 // Create list for storing importing bundles.
2385 List list = new ArrayList();
2386 Bundle[] bundles = getBundles();
2387
2388 // Check all bundles to see who imports the package.
2389 for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
2390 {
2391 BundleImpl importer = (BundleImpl) bundles[bundleIdx];
2392
Richard S. Hall82699422006-07-19 14:37:45 +00002393 // Check the import wires of all modules for all bundles.
2394 IModule[] modules = importer.getInfo().getModules();
2395 for (int modIdx = 0; modIdx < modules.length; modIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002396 {
Richard S. Hall594145f2006-07-23 13:07:18 +00002397 IWire wire = Util.getWire(modules[modIdx], ep.getName());
Richard S. Hall82699422006-07-19 14:37:45 +00002398
2399 // If the resolving module is associated with the
2400 // exporting bundle, then add current bundle to
2401 // import list.
Richard S. Hall594145f2006-07-23 13:07:18 +00002402 if ((wire != null) && exporterInfo.hasModule(wire.getExporter()))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002403 {
Richard S. Hall82699422006-07-19 14:37:45 +00002404 // Add the bundle to the list of importers.
2405 list.add(bundles[bundleIdx]);
2406 break;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002407 }
2408 }
2409 }
2410
2411 // Return the results.
2412 if (list.size() > 0)
2413 {
2414 return (Bundle[]) list.toArray(new Bundle[list.size()]);
2415 }
2416
2417 return null;
2418 }
2419
Richard S. Hall1a4ab602006-05-24 13:46:06 +00002420 protected boolean resolveBundles(Bundle[] targets)
2421 {
Richard S. Hall1a4ab602006-05-24 13:46:06 +00002422 // Acquire locks for all bundles to be resolved.
2423 BundleImpl[] bundles = acquireBundleResolveLocks(targets);
2424
2425 try
2426 {
2427 boolean result = true;
2428
2429 // If there are targets, then resolve each one.
2430 if (bundles != null)
2431 {
2432 for (int i = 0; i < bundles.length; i++)
2433 {
2434 try
2435 {
2436 _resolveBundle(bundles[i]);
2437 }
2438 catch (BundleException ex)
2439 {
2440 result = false;
2441 m_logger.log(
2442 Logger.LOG_WARNING,
2443 "Unable to resolve bundle " + bundles[i].getBundleId(),
2444 ex);
2445 }
2446 }
2447 }
2448
2449 return result;
2450 }
2451 finally
2452 {
2453 // Always release all bundle locks.
2454 releaseBundleLocks(bundles);
2455 }
2456 }
2457
Richard S. Hall930fecc2005-08-16 18:33:34 +00002458 protected void refreshPackages(Bundle[] targets)
2459 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002460 // Acquire locks for all impacted bundles.
2461 BundleImpl[] bundles = acquireBundleRefreshLocks(targets);
2462
2463 // Remove any targeted bundles from the uninstalled bundles
2464 // array, since they will be removed from the system after
2465 // the refresh.
2466 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
2467 {
2468 forgetUninstalledBundle(bundles[i]);
2469 }
2470
2471 try
2472 {
2473 // If there are targets, then refresh each one.
2474 if (bundles != null)
2475 {
2476 // At this point the map contains every bundle that has been
2477 // updated and/or removed as well as all bundles that import
2478 // packages from these bundles.
2479
2480 // Create refresh helpers for each bundle.
2481 RefreshHelper[] helpers = new RefreshHelper[bundles.length];
2482 for (int i = 0; i < bundles.length; i++)
2483 {
2484 helpers[i] = new RefreshHelper(bundles[i]);
2485 }
2486
2487 // Stop, purge or remove, and reinitialize all bundles first.
2488 for (int i = 0; i < helpers.length; i++)
2489 {
2490 helpers[i].stop();
2491 helpers[i].purgeOrRemove();
2492 helpers[i].reinitialize();
2493 }
2494
2495 // Then restart all bundles that were previously running.
2496 for (int i = 0; i < helpers.length; i++)
2497 {
2498 helpers[i].restart();
2499 }
2500 }
2501 }
2502 finally
2503 {
2504 // Always release all bundle locks.
2505 releaseBundleLocks(bundles);
2506 }
2507
2508 fireFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, getBundle(0), null);
2509 }
2510
2511 private void populateImportGraph(BundleImpl target, Map map)
2512 {
2513 // Get the exported packages for the specified bundle.
2514 ExportedPackage[] pkgs = getExportedPackages(target);
2515
2516 for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
2517 {
2518 // Get all imports of this package.
2519 Bundle[] importers = getImportingBundles(pkgs[pkgIdx]);
2520
2521 for (int impIdx = 0;
2522 (importers != null) && (impIdx < importers.length);
2523 impIdx++)
2524 {
Richard S. Halle34df092005-10-06 17:03:05 +00002525 // Avoid cycles if the bundle is already in map.
2526 if (!map.containsKey(importers[impIdx]))
2527 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002528 // Add each importing bundle to map.
2529 map.put(importers[impIdx], importers[impIdx]);
2530 // Now recurse into each bundle to get its importers.
2531 populateImportGraph(
2532 (BundleImpl) importers[impIdx], map);
Richard S. Halle34df092005-10-06 17:03:05 +00002533 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002534 }
2535 }
2536 }
2537
2538 //
2539 // Miscellaneous private methods.
2540 //
2541
Richard S. Hall04bdbb12006-03-15 14:26:15 +00002542 private BundleInfo createBundleInfo(BundleArchive archive)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002543 throws Exception
2544 {
2545 // Get the bundle manifest.
2546 Map headerMap = null;
2547 try
2548 {
2549 // Although there should only ever be one revision at this
2550 // point, get the header for the current revision to be safe.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00002551 headerMap = archive.getRevision(archive.getRevisionCount() - 1).getManifestHeader();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002552 }
2553 catch (Exception ex)
2554 {
2555 throw new BundleException("Unable to read JAR manifest.", ex);
2556 }
2557
2558 // We can't do anything without the manifest header.
2559 if (headerMap == null)
2560 {
2561 throw new BundleException("Unable to read JAR manifest header.");
2562 }
2563
2564 // Create the module for the bundle; although there should only
2565 // ever be one revision at this point, create the module for
2566 // the current revision to be safe.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002567 IModule module = createModule(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002568 archive.getId(), archive.getRevisionCount() - 1, headerMap);
2569
2570 // Finally, create an return the bundle info.
2571 return new BundleInfo(m_logger, archive, module);
2572 }
2573
2574 /**
2575 * Creates a module for a given bundle by reading the bundle's
2576 * manifest meta-data and converting it to work with the underlying
2577 * import/export search policy of the module loader.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002578 * @param targetId The identifier of the bundle for which the module should
Richard S. Hall930fecc2005-08-16 18:33:34 +00002579 * be created.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002580 * @param headerMap The headers map associated with the bundle.
Richard S. Hall930fecc2005-08-16 18:33:34 +00002581 * @return The initialized and/or newly created module.
2582 **/
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002583 private IModule createModule(long targetId, int revision, Map headerMap)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002584 throws Exception
2585 {
Richard S. Halla2878c12006-07-21 14:50:07 +00002586 ManifestParser mp = new ManifestParser(m_logger, headerMap);
2587
2588 // Verify that the bundle symbolic name and version is unique.
2589 if (mp.getVersion().equals("2"))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002590 {
Richard S. Halla2878c12006-07-21 14:50:07 +00002591 String bundleVersion = mp.get(FelixConstants.BUNDLE_VERSION);
2592 bundleVersion = (bundleVersion == null) ? "0.0.0" : bundleVersion;
2593 String symName = (String) mp.get(FelixConstants.BUNDLE_SYMBOLICNAME);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002594
Richard S. Hall8bebf412006-07-03 12:54:50 +00002595 Bundle[] bundles = getBundles();
2596 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
2597 {
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002598 long id = ((BundleImpl) bundles[i]).getInfo().getBundleId();
Richard S. Hall8bebf412006-07-03 12:54:50 +00002599 String sym = (String) ((BundleImpl) bundles[i])
2600 .getInfo().getCurrentHeader().get(Constants.BUNDLE_SYMBOLICNAME);
2601 String ver = (String) ((BundleImpl) bundles[i])
2602 .getInfo().getCurrentHeader().get(Constants.BUNDLE_VERSION);
2603 ver = (ver == null) ? "0.0.0" : ver;
Richard S. Halla2878c12006-07-21 14:50:07 +00002604 if (symName.equals(sym) && bundleVersion.equals(ver) && (targetId != id))
Richard S. Hall8bebf412006-07-03 12:54:50 +00002605 {
2606 throw new BundleException("Bundle symbolic name and version are not unique.");
2607 }
2608 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002609 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002610
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002611 // Now that we have all of the metadata associated with the
2612 // module, we need to create the module itself. This is somewhat
2613 // complicated because a module is constructed out of several
Richard S. Hall594145f2006-07-23 13:07:18 +00002614 // interrelated pieces (e.g., module definition, content loader,
2615 // search policy, url policy). We need to create all of these
2616 // pieces and bind them together.
Richard S. Hall930fecc2005-08-16 18:33:34 +00002617
Richard S. Hall594145f2006-07-23 13:07:18 +00002618 // Create the module definition for the new module.
2619 IModuleDefinition md = new ModuleDefinition(
2620 mp.getExports(),
2621 mp.getImports(),
2622 mp.getDynamicImports(),
Richard S. Halla2878c12006-07-21 14:50:07 +00002623 mp.getLibraries(
2624 m_cache,
2625 targetId,
2626 revision,
2627 m_config.get(Constants.FRAMEWORK_OS_NAME),
2628 m_config.get(Constants.FRAMEWORK_PROCESSOR)));
Richard S. Hall594145f2006-07-23 13:07:18 +00002629
2630 // Create the module using the module definition.
2631 IModule module = m_factory.createModule(
2632 Long.toString(targetId) + "." + Integer.toString(revision), md);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002633
Richard S. Hall594145f2006-07-23 13:07:18 +00002634 // Create the content loader from the module archive.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002635 IContentLoader contentLoader = new ContentLoaderImpl(
2636 m_logger,
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002637 m_cache.getArchive(targetId).getRevision(revision).getContent(),
2638 m_cache.getArchive(targetId).getRevision(revision).getContentPath());
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002639 // Set the content loader's search policy.
2640 contentLoader.setSearchPolicy(
2641 new R4SearchPolicy(m_policyCore, module));
2642 // Set the content loader's URL policy.
2643 contentLoader.setURLPolicy(
Richard S. Hallfb5221e2006-02-20 10:22:28 +00002644// TODO: ML - SUCKS NEEDING URL POLICY PER MODULE.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002645 new URLPolicyImpl(
2646 m_logger, m_bundleStreamHandler, module));
2647
2648 // Set the module's content loader to the created content loader.
2649 m_factory.setContentLoader(module, contentLoader);
2650
2651 // Done, so return the module.
Richard S. Hall930fecc2005-08-16 18:33:34 +00002652 return module;
2653 }
2654
2655 private BundleActivator createBundleActivator(BundleInfo info)
2656 throws Exception
2657 {
2658 // CONCURRENCY NOTE:
2659 // This method is called indirectly from startBundle() (via _startBundle()),
2660 // which has the exclusion lock, so there is no need to do any locking here.
2661
2662 BundleActivator activator = null;
2663
2664 String strict = m_config.get(FelixConstants.STRICT_OSGI_PROP);
2665 boolean isStrict = (strict == null) ? true : strict.equals("true");
2666 if (!isStrict)
2667 {
2668 try
2669 {
2670 activator =
2671 m_cache.getArchive(info.getBundleId())
Richard S. Hallf1359482006-02-14 08:02:51 +00002672 .getActivator(info.getCurrentModule());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002673 }
2674 catch (Exception ex)
2675 {
2676 activator = null;
2677 }
2678 }
2679
2680 // If there was no cached activator, then get the activator
2681 // class from the bundle manifest.
2682 if (activator == null)
2683 {
2684 // Get the associated bundle archive.
Richard S. Hall04bdbb12006-03-15 14:26:15 +00002685 BundleArchive ba = m_cache.getArchive(info.getBundleId());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002686 // Get the manifest from the current revision; revision is
2687 // base zero so subtract one from the count to get the
2688 // current revision.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00002689 Map headerMap = ba.getRevision(ba.getRevisionCount() - 1).getManifestHeader();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002690 // Get the activator class attribute.
2691 String className = (String) headerMap.get(Constants.BUNDLE_ACTIVATOR);
2692 // Try to instantiate activator class if present.
2693 if (className != null)
2694 {
2695 className = className.trim();
Richard S. Hall6b5f96c2006-02-10 15:57:15 +00002696 Class clazz = info.getCurrentModule().getClass(className);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002697 if (clazz == null)
2698 {
2699 throw new BundleException("Not found: "
Richard S. Hall56c68832006-06-23 15:27:31 +00002700 + className, new ClassNotFoundException(className));
Richard S. Hall930fecc2005-08-16 18:33:34 +00002701 }
2702 activator = (BundleActivator) clazz.newInstance();
2703 }
2704 }
2705
2706 return activator;
2707 }
2708
2709 private void purgeBundle(BundleImpl bundle) throws Exception
2710 {
2711 // Acquire bundle lock.
2712 acquireBundleLock(bundle);
2713
2714 try
2715 {
2716 BundleInfo info = bundle.getInfo();
2717
2718 // In case of a refresh, then we want to physically
2719 // remove the bundle's modules from the module manager.
2720 // This is necessary for two reasons: 1) because
2721 // under Windows we won't be able to delete the bundle
2722 // because files might be left open in the resource
2723 // sources of its modules and 2) we want to make sure
2724 // that no references to old modules exist since they
2725 // will all be stale after the refresh. The only other
2726 // way to do this is to remove the bundle, but that
2727 // would be incorrect, because this is a refresh operation
2728 // and should not trigger bundle REMOVE events.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002729 IModule[] modules = info.getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002730 for (int i = 0; i < modules.length; i++)
2731 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002732 m_factory.removeModule(modules[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002733 }
2734
2735 // Purge all bundle revisions, but the current one.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00002736 m_cache.getArchive(info.getBundleId()).purge();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002737 }
2738 finally
2739 {
2740 // Always release the bundle lock.
2741 releaseBundleLock(bundle);
2742 }
2743 }
2744
2745 private void garbageCollectBundle(BundleImpl bundle) throws Exception
2746 {
2747 // CONCURRENCY NOTE: There is no reason to lock this bundle,
2748 // because this method is only called during shutdown or a
2749 // refresh operation and these are already guarded by locks.
2750
2751 // Remove the bundle's associated modules from
2752 // the module manager.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002753 IModule[] modules = bundle.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002754 for (int i = 0; i < modules.length; i++)
2755 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002756 m_factory.removeModule(modules[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002757 }
2758
2759 // Remove the bundle from the cache.
2760 m_cache.remove(m_cache.getArchive(bundle.getInfo().getBundleId()));
2761 }
2762
2763 //
2764 // Event-related methods.
2765 //
2766
2767 /**
2768 * Fires bundle events.
2769 **/
2770 private void fireFrameworkEvent(
2771 int type, Bundle bundle, Throwable throwable)
2772 {
Richard S. Hall92770632006-07-24 10:18:52 +00002773 m_dispatcher.fireFrameworkEvent(new FrameworkEvent(type, bundle, throwable));
Richard S. Hall930fecc2005-08-16 18:33:34 +00002774 }
2775
2776 /**
2777 * Fires bundle events.
2778 *
2779 * @param type The type of bundle event to fire.
2780 * @param bundle The bundle associated with the event.
2781 **/
2782 private void fireBundleEvent(int type, Bundle bundle)
2783 {
Richard S. Hall92770632006-07-24 10:18:52 +00002784 m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle));
Richard S. Hall930fecc2005-08-16 18:33:34 +00002785 }
2786
2787 /**
2788 * Fires service events.
2789 *
2790 * @param type The type of service event to fire.
2791 * @param ref The service reference associated with the event.
2792 **/
2793 private void fireServiceEvent(ServiceEvent event)
2794 {
Richard S. Hall92770632006-07-24 10:18:52 +00002795 m_dispatcher.fireServiceEvent(event);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002796 }
2797
2798 //
2799 // Property related methods.
2800 //
2801
2802 private void initializeFrameworkProperties()
2803 {
2804 // Standard OSGi properties.
Richard S. Hallea415752005-12-05 19:30:28 +00002805 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002806 FelixConstants.FRAMEWORK_VERSION,
2807 FelixConstants.FRAMEWORK_VERSION_VALUE);
Richard S. Hallea415752005-12-05 19:30:28 +00002808 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002809 FelixConstants.FRAMEWORK_VENDOR,
2810 FelixConstants.FRAMEWORK_VENDOR_VALUE);
Richard S. Hallea415752005-12-05 19:30:28 +00002811 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002812 FelixConstants.FRAMEWORK_LANGUAGE,
2813 System.getProperty("user.language"));
Richard S. Hallea415752005-12-05 19:30:28 +00002814 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002815 FelixConstants.FRAMEWORK_OS_VERSION,
2816 System.getProperty("os.version"));
2817
2818 String s = null;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002819 s = R4Library.normalizePropertyValue(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002820 FelixConstants.FRAMEWORK_OS_NAME,
2821 System.getProperty("os.name"));
Richard S. Hallea415752005-12-05 19:30:28 +00002822 m_configMutable.put(FelixConstants.FRAMEWORK_OS_NAME, s);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002823 s = R4Library.normalizePropertyValue(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002824 FelixConstants.FRAMEWORK_PROCESSOR,
2825 System.getProperty("os.arch"));
Richard S. Hallea415752005-12-05 19:30:28 +00002826 m_configMutable.put(FelixConstants.FRAMEWORK_PROCESSOR, s);
Richard S. Hallea415752005-12-05 19:30:28 +00002827 m_configMutable.put(
Richard S. Hall03ddc842006-03-09 14:50:16 +00002828 FelixConstants.FELIX_VERSION_PROPERTY, getFrameworkVersion());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002829 }
2830
Richard S. Hall03ddc842006-03-09 14:50:16 +00002831 /**
2832 * Read the framework version from the property file.
2833 * @return the framework version as a string.
2834 **/
2835 private static String getFrameworkVersion()
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00002836 {
2837 // The framework version property.
2838 Properties props = new Properties();
Richard S. Hall03ddc842006-03-09 14:50:16 +00002839 InputStream in = Felix.class.getResourceAsStream("Felix.properties");
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00002840 try
2841 {
Richard S. Hall03ddc842006-03-09 14:50:16 +00002842 props.load(in);
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00002843 }
Richard S. Hall03ddc842006-03-09 14:50:16 +00002844 catch (IOException ex)
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00002845 {
Richard S. Hall03ddc842006-03-09 14:50:16 +00002846 ex.printStackTrace();
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00002847 }
Richard S. Halla155e2e2006-03-09 21:20:02 +00002848
2849 // Maven uses a '-' to separate the version qualifier,
2850 // while OSGi uses a '.', so we need to convert to a '.'
2851 StringBuffer sb =
2852 new StringBuffer(
2853 props.getProperty(
2854 FelixConstants.FELIX_VERSION_PROPERTY, "unknown"));
Richard S. Hall1615e552006-05-30 14:10:06 +00002855 if (sb.toString().indexOf("-") >= 0)
Richard S. Halla155e2e2006-03-09 21:20:02 +00002856 {
Richard S. Hall1615e552006-05-30 14:10:06 +00002857 sb.setCharAt(sb.toString().indexOf("-"), '.');
Richard S. Halla155e2e2006-03-09 21:20:02 +00002858 }
2859 return sb.toString();
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00002860 }
2861
Richard S. Hall930fecc2005-08-16 18:33:34 +00002862 private void processAutoProperties()
2863 {
2864 // The auto-install property specifies a space-delimited list of
2865 // bundle URLs to be automatically installed into each new profile;
2866 // the start level to which the bundles are assigned is specified by
2867 // appending a ".n" to the auto-install property name, where "n" is
2868 // the desired start level for the list of bundles.
2869 String[] keys = m_config.getKeys();
2870 for (int i = 0; (keys != null) && (i < keys.length); i++)
2871 {
2872 if (keys[i].startsWith(FelixConstants.AUTO_INSTALL_PROP))
2873 {
2874 int startLevel = 1;
2875 try
2876 {
2877 startLevel = Integer.parseInt(keys[i].substring(keys[i].lastIndexOf('.') + 1));
2878 }
2879 catch (NumberFormatException ex)
2880 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002881 m_logger.log(Logger.LOG_ERROR, "Invalid property: " + keys[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002882 }
2883 StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
2884 if (st.countTokens() > 0)
2885 {
2886 String location = null;
2887 do
2888 {
2889 location = nextLocation(st);
2890 if (location != null)
2891 {
2892 try
2893 {
2894 BundleImpl b = (BundleImpl) installBundle(location, null);
2895 b.getInfo().setStartLevel(startLevel);
2896 }
2897 catch (Exception ex)
2898 {
2899 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002900 Logger.LOG_ERROR, "Auto-properties install.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002901 }
2902 }
2903 }
2904 while (location != null);
2905 }
2906 }
2907 }
2908
2909 // The auto-start property specifies a space-delimited list of
2910 // bundle URLs to be automatically installed and started into each
2911 // new profile; the start level to which the bundles are assigned
2912 // is specified by appending a ".n" to the auto-start property name,
2913 // where "n" is the desired start level for the list of bundles.
2914 // The following code starts bundles in two passes, first it installs
2915 // them, then it starts them.
2916 for (int i = 0; (keys != null) && (i < keys.length); i++)
2917 {
2918 if (keys[i].startsWith(FelixConstants.AUTO_START_PROP))
2919 {
2920 int startLevel = 1;
2921 try
2922 {
2923 startLevel = Integer.parseInt(keys[i].substring(keys[i].lastIndexOf('.') + 1));
2924 }
2925 catch (NumberFormatException ex)
2926 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002927 m_logger.log(Logger.LOG_ERROR, "Invalid property: " + keys[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002928 }
2929 StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
2930 if (st.countTokens() > 0)
2931 {
2932 String location = null;
2933 do
2934 {
2935 location = nextLocation(st);
2936 if (location != null)
2937 {
2938 try
2939 {
2940 BundleImpl b = (BundleImpl) installBundle(location, null);
2941 b.getInfo().setStartLevel(startLevel);
2942 }
2943 catch (Exception ex)
2944 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002945 m_logger.log(Logger.LOG_ERROR, "Auto-properties install.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002946 }
2947 }
2948 }
2949 while (location != null);
2950 }
2951 }
2952 }
2953
2954 // Now loop through and start the installed bundles.
2955 for (int i = 0; (keys != null) && (i < keys.length); i++)
2956 {
2957 if (keys[i].startsWith(FelixConstants.AUTO_START_PROP))
2958 {
2959 StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
2960 if (st.countTokens() > 0)
2961 {
2962 String location = null;
2963 do
2964 {
2965 location = nextLocation(st);
2966 if (location != null)
2967 {
2968 // Installing twice just returns the same bundle.
2969 try
2970 {
2971 BundleImpl bundle = (BundleImpl) installBundle(location, null);
2972 if (bundle != null)
2973 {
2974 startBundle(bundle, true);
2975 }
2976 }
2977 catch (Exception ex)
2978 {
2979 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002980 Logger.LOG_ERROR, "Auto-properties start.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002981 }
2982 }
2983 }
2984 while (location != null);
2985 }
2986 }
2987 }
2988 }
2989
2990 private String nextLocation(StringTokenizer st)
2991 {
2992 String retVal = null;
2993
2994 if (st.countTokens() > 0)
2995 {
2996 String tokenList = "\" ";
2997 StringBuffer tokBuf = new StringBuffer(10);
2998 String tok = null;
2999 boolean inQuote = false;
3000 boolean tokStarted = false;
3001 boolean exit = false;
3002 while ((st.hasMoreTokens()) && (!exit))
3003 {
3004 tok = st.nextToken(tokenList);
3005 if (tok.equals("\""))
3006 {
3007 inQuote = ! inQuote;
3008 if (inQuote)
3009 {
3010 tokenList = "\"";
3011 }
3012 else
3013 {
3014 tokenList = "\" ";
3015 }
3016
3017 }
3018 else if (tok.equals(" "))
3019 {
3020 if (tokStarted)
3021 {
3022 retVal = tokBuf.toString();
3023 tokStarted=false;
3024 tokBuf = new StringBuffer(10);
3025 exit = true;
3026 }
3027 }
3028 else
3029 {
3030 tokStarted = true;
3031 tokBuf.append(tok.trim());
3032 }
3033 }
3034
3035 // Handle case where end of token stream and
3036 // still got data
3037 if ((!exit) && (tokStarted))
3038 {
3039 retVal = tokBuf.toString();
3040 }
3041 }
3042
3043 return retVal;
3044 }
3045
3046 //
3047 // Private utility methods.
3048 //
3049
3050 /**
3051 * Generated the next valid bundle identifier.
3052 **/
Richard S. Hall441c7152006-02-17 11:07:10 +00003053 private long getNextId()
Richard S. Hall930fecc2005-08-16 18:33:34 +00003054 {
Richard S. Hall441c7152006-02-17 11:07:10 +00003055 synchronized (m_nextIdLock)
3056 {
3057 return m_nextId++;
3058 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003059 }
3060
3061 //
3062 // Configuration methods and inner classes.
3063 //
3064
3065 public PropertyResolver getConfig()
3066 {
3067 return m_config;
3068 }
3069
3070 private class ConfigImpl implements PropertyResolver
3071 {
3072 public String get(String key)
3073 {
Richard S. Hallea415752005-12-05 19:30:28 +00003074 return (m_configMutable == null) ? null : m_configMutable.get(key);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003075 }
3076
3077 public String[] getKeys()
3078 {
Richard S. Hallea415752005-12-05 19:30:28 +00003079 return m_configMutable.getKeys();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003080 }
3081 }
3082
3083 //
3084 // Logging methods and inner classes.
3085 //
3086
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003087 public Logger getLogger()
Richard S. Hall930fecc2005-08-16 18:33:34 +00003088 {
3089 return m_logger;
3090 }
3091
3092 /**
3093 * Simple class that is used in <tt>refreshPackages()</tt> to embody
3094 * the refresh logic in order to keep the code clean. This class is
3095 * not static because it needs access to framework event firing methods.
3096 **/
3097 private class RefreshHelper
3098 {
3099 private BundleImpl m_bundle = null;
3100
3101 public RefreshHelper(Bundle bundle)
3102 {
3103 m_bundle = (BundleImpl) bundle;
3104 }
3105
3106 public void stop()
3107 {
3108 if (m_bundle.getInfo().getState() == Bundle.ACTIVE)
3109 {
3110 try
3111 {
3112 stopBundle(m_bundle, false);
3113 }
3114 catch (BundleException ex)
3115 {
3116 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3117 }
3118 }
3119 }
3120
3121 public void purgeOrRemove()
3122 {
3123 try
3124 {
3125 BundleInfo info = m_bundle.getInfo();
3126
Richard S. Halle1f53a52006-07-17 11:06:59 +00003127 // Mark the bundle as stale.
3128 info.setStale();
3129
Richard S. Hall930fecc2005-08-16 18:33:34 +00003130 // Remove or purge the bundle depending on its
3131 // current state.
3132 if (info.getState() == Bundle.UNINSTALLED)
3133 {
3134 // This physically removes the bundle from memory
3135 // as well as the bundle cache.
3136 garbageCollectBundle(m_bundle);
3137 m_bundle = null;
3138 }
3139 else
3140 {
3141 // This physically removes all old revisions of the
3142 // bundle from memory and only maintains the newest
3143 // version in the bundle cache.
3144 purgeBundle(m_bundle);
3145 }
3146 }
3147 catch (Exception ex)
3148 {
3149 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3150 }
3151 }
3152
3153 public void reinitialize()
3154 {
3155 if (m_bundle != null)
3156 {
3157 try
3158 {
3159 BundleInfo info = m_bundle.getInfo();
3160 BundleInfo newInfo = createBundleInfo(info.getArchive());
3161 newInfo.syncLock(info);
3162 m_bundle.setInfo(newInfo);
3163 }
3164 catch (Exception ex)
3165 {
3166 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3167 }
3168 }
3169 }
3170
3171 public void restart()
3172 {
3173 if (m_bundle != null)
3174 {
3175 try
3176 {
3177 startBundle(m_bundle, false);
3178 }
3179 catch (BundleException ex)
3180 {
3181 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3182 }
3183 }
3184 }
3185 }
3186
3187 //
3188 // Locking related methods.
3189 //
3190
3191 private void rememberUninstalledBundle(BundleImpl bundle)
3192 {
3193 synchronized (m_uninstalledBundlesLock_Priority3)
3194 {
3195 // Verify that the bundle is not already in the array.
3196 for (int i = 0;
3197 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
3198 i++)
3199 {
3200 if (m_uninstalledBundles[i] == bundle)
3201 {
3202 return;
3203 }
3204 }
3205
3206 if (m_uninstalledBundles != null)
3207 {
3208 BundleImpl[] newBundles =
3209 new BundleImpl[m_uninstalledBundles.length + 1];
3210 System.arraycopy(m_uninstalledBundles, 0,
3211 newBundles, 0, m_uninstalledBundles.length);
3212 newBundles[m_uninstalledBundles.length] = bundle;
3213 m_uninstalledBundles = newBundles;
3214 }
3215 else
3216 {
3217 m_uninstalledBundles = new BundleImpl[] { bundle };
3218 }
3219 }
3220 }
3221
3222 private void forgetUninstalledBundle(BundleImpl bundle)
3223 {
3224 synchronized (m_uninstalledBundlesLock_Priority3)
3225 {
3226 if (m_uninstalledBundles == null)
3227 {
3228 return;
3229 }
3230
3231 int idx = -1;
3232 for (int i = 0; i < m_uninstalledBundles.length; i++)
3233 {
3234 if (m_uninstalledBundles[i] == bundle)
3235 {
3236 idx = i;
3237 break;
3238 }
3239 }
3240
3241 if (idx >= 0)
3242 {
3243 // If this is the only bundle, then point to empty list.
3244 if ((m_uninstalledBundles.length - 1) == 0)
3245 {
3246 m_uninstalledBundles = new BundleImpl[0];
3247 }
3248 // Otherwise, we need to do some array copying.
3249 else
3250 {
3251 BundleImpl[] newBundles =
3252 new BundleImpl[m_uninstalledBundles.length - 1];
3253 System.arraycopy(m_uninstalledBundles, 0, newBundles, 0, idx);
3254 if (idx < newBundles.length)
3255 {
3256 System.arraycopy(
3257 m_uninstalledBundles, idx + 1,
3258 newBundles, idx, newBundles.length - idx);
3259 }
3260 m_uninstalledBundles = newBundles;
3261 }
3262 }
3263 }
3264 }
3265
3266 protected void acquireInstallLock(String location)
3267 throws BundleException
3268 {
3269 synchronized (m_installRequestLock_Priority1)
3270 {
3271 while (m_installRequestMap.get(location) != null)
3272 {
3273 try
3274 {
3275 m_installRequestLock_Priority1.wait();
3276 }
3277 catch (InterruptedException ex)
3278 {
3279 throw new BundleException("Unable to install, thread interrupted.");
3280 }
3281 }
3282
3283 m_installRequestMap.put(location, location);
3284 }
3285 }
3286
3287 protected void releaseInstallLock(String location)
3288 {
3289 synchronized (m_installRequestLock_Priority1)
3290 {
3291 m_installRequestMap.remove(location);
3292 m_installRequestLock_Priority1.notifyAll();
3293 }
3294 }
3295
3296 protected void acquireBundleLock(BundleImpl bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003297 {
3298 synchronized (m_bundleLock)
3299 {
3300 while (!bundle.getInfo().isLockable())
3301 {
3302 try
3303 {
3304 m_bundleLock.wait();
3305 }
3306 catch (InterruptedException ex)
3307 {
3308 // Ignore and just keep waiting.
3309 }
3310 }
3311 bundle.getInfo().lock();
3312 }
3313 }
3314
Richard S. Hall3c26cc02006-02-17 13:51:21 +00003315 protected boolean acquireBundleLockOrFail(BundleImpl bundle)
3316 {
3317 synchronized (m_bundleLock)
3318 {
3319 if (!bundle.getInfo().isLockable())
3320 {
3321 return false;
3322 }
3323 bundle.getInfo().lock();
3324 return true;
3325 }
3326 }
3327
Richard S. Hall930fecc2005-08-16 18:33:34 +00003328 protected void releaseBundleLock(BundleImpl bundle)
3329 {
3330 synchronized (m_bundleLock)
3331 {
3332 bundle.getInfo().unlock();
3333 m_bundleLock.notifyAll();
3334 }
3335 }
3336
Richard S. Hall1a4ab602006-05-24 13:46:06 +00003337 protected BundleImpl[] acquireBundleResolveLocks(Bundle[] targets)
3338 {
3339 // Hold bundles to be locked.
3340 BundleImpl[] bundles = null;
3341 // Convert existing target bundle array to bundle impl array.
3342 if (targets != null)
3343 {
3344 bundles = new BundleImpl[targets.length];
3345 for (int i = 0; i < targets.length; i++)
3346 {
3347 bundles[i] = (BundleImpl) targets[i];
3348 }
3349 }
3350
3351 synchronized (m_bundleLock)
3352 {
3353 boolean success = false;
3354 while (!success)
3355 {
3356 // If targets is null, then resolve all unresolved bundles.
3357 if (targets == null)
3358 {
3359 List list = new ArrayList();
3360
3361 // Add all unresolved bundles to the list.
3362 synchronized (m_installedBundleLock_Priority2)
3363 {
3364 Iterator iter = m_installedBundleMap.values().iterator();
3365 while (iter.hasNext())
3366 {
3367 BundleImpl bundle = (BundleImpl) iter.next();
3368 if (bundle.getInfo().getState() == Bundle.INSTALLED)
3369 {
3370 list.add(bundle);
3371 }
3372 }
3373 }
3374
3375 // Create an array.
3376 if (list.size() > 0)
3377 {
3378 bundles = (BundleImpl[]) list.toArray(new BundleImpl[list.size()]);
3379 }
3380 }
3381
3382 // Check if all unresolved bundles can be locked.
3383 boolean lockable = true;
3384 if (bundles != null)
3385 {
3386 for (int i = 0; lockable && (i < bundles.length); i++)
3387 {
3388 lockable = bundles[i].getInfo().isLockable();
3389 }
3390
3391 // If we can lock all bundles, then lock them.
3392 if (lockable)
3393 {
3394 for (int i = 0; i < bundles.length; i++)
3395 {
3396 bundles[i].getInfo().lock();
3397 }
3398 success = true;
3399 }
3400 // Otherwise, wait and try again.
3401 else
3402 {
3403 try
3404 {
3405 m_bundleLock.wait();
3406 }
3407 catch (InterruptedException ex)
3408 {
3409 // Ignore and just keep waiting.
3410 }
3411 }
3412 }
3413 else
3414 {
3415 // If there were no bundles to lock, then we can just
3416 // exit the lock loop.
3417 success = true;
3418 }
3419 }
3420 }
3421
3422 return bundles;
3423 }
3424
Richard S. Hall930fecc2005-08-16 18:33:34 +00003425 protected BundleImpl[] acquireBundleRefreshLocks(Bundle[] targets)
3426 {
3427 // Hold bundles to be locked.
3428 BundleImpl[] bundles = null;
3429
3430 synchronized (m_bundleLock)
3431 {
3432 boolean success = false;
3433 while (!success)
3434 {
3435 // If targets is null, then refresh all pending bundles.
3436 Bundle[] newTargets = targets;
3437 if (newTargets == null)
3438 {
3439 List list = new ArrayList();
3440
3441 // First add all uninstalled bundles.
3442 synchronized (m_uninstalledBundlesLock_Priority3)
3443 {
3444 for (int i = 0;
3445 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
3446 i++)
3447 {
3448 list.add(m_uninstalledBundles[i]);
3449 }
3450 }
3451
3452 // Then add all updated bundles.
3453 synchronized (m_installedBundleLock_Priority2)
3454 {
3455 Iterator iter = m_installedBundleMap.values().iterator();
3456 while (iter.hasNext())
3457 {
3458 BundleImpl bundle = (BundleImpl) iter.next();
Richard S. Hall60c26d42006-07-19 10:35:04 +00003459 if (bundle.getInfo().getArchive().getRevisionCount() > 1)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003460 {
3461 list.add(bundle);
3462 }
3463 }
3464 }
3465
3466 // Create an array.
3467 if (list.size() > 0)
3468 {
3469 newTargets = (Bundle[]) list.toArray(new Bundle[list.size()]);
3470 }
3471 }
3472
3473 // If there are targets, then find all dependencies
3474 // for each one.
3475 if (newTargets != null)
3476 {
3477 // Create map of bundles that import the packages
3478 // from the target bundles.
3479 Map map = new HashMap();
3480 for (int targetIdx = 0; targetIdx < newTargets.length; targetIdx++)
3481 {
3482 // Add the current target bundle to the map of
3483 // bundles to be refreshed.
3484 BundleImpl target = (BundleImpl) newTargets[targetIdx];
3485 map.put(target, target);
3486 // Add all importing bundles to map.
3487 populateImportGraph(target, map);
3488 }
3489
3490 bundles = (BundleImpl[]) map.values().toArray(new BundleImpl[map.size()]);
3491 }
3492
Richard S. Hall1a4ab602006-05-24 13:46:06 +00003493 // Check if all corresponding bundles can be locked.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003494 boolean lockable = true;
3495 if (bundles != null)
3496 {
3497 for (int i = 0; lockable && (i < bundles.length); i++)
3498 {
3499 lockable = bundles[i].getInfo().isLockable();
3500 }
3501
3502 // If we can lock all bundles, then lock them.
3503 if (lockable)
3504 {
3505 for (int i = 0; i < bundles.length; i++)
3506 {
3507 bundles[i].getInfo().lock();
3508 }
3509 success = true;
3510 }
3511 // Otherwise, wait and try again.
3512 else
3513 {
3514 try
3515 {
3516 m_bundleLock.wait();
3517 }
3518 catch (InterruptedException ex)
3519 {
3520 // Ignore and just keep waiting.
3521 }
3522 }
3523 }
3524 else
3525 {
3526 // If there were no bundles to lock, then we can just
3527 // exit the lock loop.
3528 success = true;
3529 }
3530 }
3531 }
3532
3533 return bundles;
3534 }
3535
3536 protected void releaseBundleLocks(BundleImpl[] bundles)
3537 {
3538 // Always unlock any locked bundles.
3539 synchronized (m_bundleLock)
3540 {
3541 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
3542 {
3543 bundles[i].getInfo().unlock();
3544 }
3545 m_bundleLock.notifyAll();
3546 }
3547 }
Karl Paulsc19abb42006-07-21 10:23:11 +00003548
3549 private static class PrivilegedActivatorCall implements
3550 java.security.PrivilegedExceptionAction
3551 {
3552 private static final int START = 1;
3553 private static final int STOP = 2;
3554 private int m_action;
3555 private BundleActivator m_activator;
3556 private BundleContext m_context;
3557
3558 PrivilegedActivatorCall(int action, BundleActivator activator, BundleContext context)
3559 {
3560 m_action = action;
3561 m_activator = activator;
3562 m_context = context;
3563 }
3564 public Object run() throws Exception
3565 {
3566 switch (m_action)
3567 {
3568 case START:
3569 m_activator.start(m_context);
3570 break;
3571 case STOP:
3572 m_activator.stop(m_context);
3573 break;
3574 default:
3575 throw new IllegalStateException("Unknown activator action.");
3576 }
3577
3578 return null;
3579 }
3580 }
3581
3582 /**
3583 * This simple class is used to perform the privileged action of
3584 * checking if a bundle has permission to import its packages.
3585 **/
3586 private class CheckImportsPrivileged implements java.security.PrivilegedExceptionAction
3587 {
3588 private URL m_url = null;
3589 private BundleImpl m_bundle = null;
3590
3591 public CheckImportsPrivileged(URL url, BundleImpl bundle)
3592 {
3593 m_url = url;
3594 m_bundle = bundle;
3595 }
3596
3597 public Object run() throws Exception
3598 {
3599 // Get permission collection for code source; we cannot
3600 // call AccessController.checkPermission() directly since
3601 // the bundle's code is not on the access context yet because
3602 // it has not started yet...we are simply resolving it to see
3603 // if we can start it. We must check for import permission
3604 // on the exports as well, since export implies import.
3605 java.security.CodeSource cs = new java.security.CodeSource(m_url,
3606 (java.security.cert.Certificate[]) null);
3607
3608 java.security.PermissionCollection pc =
3609 java.security.Policy.getPolicy().getPermissions(cs);
3610
Richard S. Hall594145f2006-07-23 13:07:18 +00003611 R4Import[] imports =
3612 m_bundle.getInfo().getCurrentModule().getDefinition().getImports();
Karl Paulsc19abb42006-07-21 10:23:11 +00003613
3614 for (int i = 0;i < imports.length; i++)
3615 {
3616 PackagePermission perm = new PackagePermission(imports[i].getName(),
3617 PackagePermission.IMPORT);
3618 if (!pc.implies(perm))
3619 {
3620 throw new java.security.AccessControlException(
3621 "PackagePermission.IMPORT denied for import: " +
3622 imports[i].getName(), perm);
3623 }
3624 }
3625 // Check export permission for all exports of the current module.
Richard S. Hall594145f2006-07-23 13:07:18 +00003626 R4Export[] implicitImports =
3627 m_bundle.getInfo().getCurrentModule().getDefinition().getExports();
Karl Paulsc19abb42006-07-21 10:23:11 +00003628
3629 for (int i = 0;i < implicitImports.length; i++)
3630 {
3631 PackagePermission perm = new PackagePermission(
3632 implicitImports[i].getName(), PackagePermission.EXPORT);
3633 if (!pc.implies(perm))
3634 {
3635 throw new java.security.AccessControlException(
3636 "PackagePermission.EXPORT denied for implicit export: " +
3637 implicitImports[i].getName(), perm);
3638 }
3639 }
3640
3641 return null;
3642 }
3643 }
Richard S. Hall9a3e9852006-03-04 03:44:05 +00003644}