blob: de9870798f70196264c7eed49d24a6ab84c3f80d [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.*;
21import java.security.AccessController;
22import java.security.PrivilegedActionException;
23import java.util.*;
24
Richard S. Hall5a031592005-08-19 19:53:58 +000025import org.apache.felix.framework.cache.*;
26import org.apache.felix.framework.searchpolicy.*;
27import org.apache.felix.framework.util.*;
Richard S. Hall5a031592005-08-19 19:53:58 +000028import org.apache.felix.moduleloader.*;
Richard S. Hall930fecc2005-08-16 18:33:34 +000029import org.osgi.framework.*;
30import org.osgi.service.packageadmin.ExportedPackage;
Richard S. Hall17897152006-03-02 13:43:09 +000031import org.osgi.service.startlevel.StartLevel;
Richard S. Hall930fecc2005-08-16 18:33:34 +000032
33public class Felix
34{
35 // Logging related member variables.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +000036 private Logger m_logger = new Logger();
Richard S. Hall930fecc2005-08-16 18:33:34 +000037 // Config properties.
38 private PropertyResolver m_config = new ConfigImpl();
39 // Configuration properties passed into constructor.
Richard S. Hallea415752005-12-05 19:30:28 +000040 private MutablePropertyResolver m_configMutable = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000041
Richard S. Hall29a4fbc2006-02-03 12:54:52 +000042 // MODULE FACTORY.
43 private IModuleFactory m_factory = null;
44 private R4SearchPolicyCore m_policyCore = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000045
46 // Object used as a lock when calculating which bundles
47 // when performing an operation on one or more bundles.
48 private Object[] m_bundleLock = new Object[0];
49
50 // Maps a bundle location to a bundle location;
51 // used to reserve a location when installing a bundle.
52 private Map m_installRequestMap = null;
53 // This lock must be acquired to modify m_installRequestMap;
54 // to help avoid deadlock this lock as priority 1 and should
55 // be acquired before locks with lower priority.
56 private Object[] m_installRequestLock_Priority1 = new Object[0];
57
58 // Maps a bundle location to a bundle.
59 private HashMap m_installedBundleMap = null;
60 // This lock must be acquired to modify m_installedBundleMap;
61 // to help avoid deadlock this lock as priority 2 and should
62 // be acquired before locks with lower priority.
63 private Object[] m_installedBundleLock_Priority2 = new Object[0];
64
65 // An array of uninstalled bundles before a refresh occurs.
66 private BundleImpl[] m_uninstalledBundles = null;
67 // This lock must be acquired to modify m_uninstalledBundles;
68 // to help avoid deadlock this lock as priority 3 and should
69 // be acquired before locks with lower priority.
70 private Object[] m_uninstalledBundlesLock_Priority3 = new Object[0];
71
72 // Status flag for framework.
73 public static final int INITIAL_STATUS = -1;
74 public static final int RUNNING_STATUS = 0;
75 public static final int STARTING_STATUS = 1;
76 public static final int STOPPING_STATUS = 2;
77 private int m_frameworkStatus = INITIAL_STATUS;
78
79 // Framework's active start level.
80 private int m_activeStartLevel =
81 FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
82
83 // Local file system cache.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +000084 private DefaultBundleCache m_cache = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000085
86 // Next available bundle identifier.
87 private long m_nextId = 1L;
Richard S. Hall441c7152006-02-17 11:07:10 +000088 private Object m_nextIdLock = new Object[0];
Richard S. Hall930fecc2005-08-16 18:33:34 +000089
90 // List of event listeners.
91 private FelixDispatchQueue m_dispatchQueue = null;
92 // Re-usable event dispatchers.
93 private Dispatcher m_frameworkDispatcher = null;
94 private Dispatcher m_bundleDispatcher = null;
95 private Dispatcher m_serviceDispatcher = null;
96
97 // Service registry.
98 private ServiceRegistry m_registry = null;
99
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000100 // Reusable bundle URL stream handler.
101 private URLStreamHandler m_bundleStreamHandler = null;
102
Richard S. Hall930fecc2005-08-16 18:33:34 +0000103 // Reusable admin permission object for all instances
104 // of the BundleImpl.
105 private static AdminPermission m_adminPerm = new AdminPermission();
106
107 /**
108 * <p>
109 * This method starts the framework instance; instances of the framework
110 * are dormant until this method is called. The caller may also provide
111 * <tt>MutablePropertyResolver</tt> implementations that the instance will
112 * use to obtain configuration or framework properties. Configuration
113 * properties are used internally by the framework and its extensions to alter
114 * its default behavior. Framework properties are used by bundles
115 * and are accessible from <tt>BundleContext.getProperty()</tt>.
116 * </p>
117 * <p>
118 * Configuration properties are the sole means to configure the framework's
119 * default behavior; the framework does not refer to any system properties for
120 * configuration information. If a <tt>MutablePropertyResolver</tt> is
121 * supplied to this method for configuration properties, then the framework will
122 * consult the <tt>MutablePropertyResolver</tt> instance for any and all
123 * configuration properties. It is possible to specify a <tt>null</tt>
124 * configuration property resolver, in which case the framework will use its
125 * default behavior in all cases. However, if the
126 * <a href="cache/DefaultBundleCache.html"><tt>DefaulBundleCache</tt></a>
127 * is used, then at a minimum a profile name or profile directory must
128 * be specified.
129 * </p>
130 * <p>
131 * The following configuration properties can be specified:
132 * </p>
133 * <ul>
134 * <li><tt>felix.cache.class</tt> - The class name to be used when
135 * creating an instance for the bundle cache; this class must
136 * implement the <tt>BundleCache</tt> interface and have a default
137 * constructor. By default, the framework will create an instance of
138 * <tt>DefaultBundleCache</tt> for the bundle cache.
139 * </li>
140 * <li><tt>felix.auto.install.&lt;n&gt;</tt> - Space-delimited list of
141 * bundles to automatically install into start level <tt>n</tt> when
142 * the framework is started. Append a specific start level to this
143 * property name to assign the bundles' start level
144 * (e.g., <tt>felix.auto.install.2</tt>).
145 * </li>
146 * <li><tt>felix.auto.start.&lt;n&gt;</tt> - Space-delimited list of
147 * bundles to automatically install and start into start level
148 * <tt>n</tt> when the framework is started. Append a
149 * specific start level to this property name to assign the
150 * bundles' start level(e.g., <tt>felix.auto.start.2</tt>).
151 * </li>
152 * <li><tt>felix.startlevel.framework</tt> - The initial start level
153 * of the framework once it starts execution; the default
154 * value is 1.
155 * </li>
156 * <li><tt>felix.startlevel.bundle</tt> - The default start level for
157 * newly installed bundles; the default value is 1.
158 * </li>
Richard S. Hall5d226732005-11-08 09:09:05 +0000159 * <li><tt>framework.service.urlhandlers</tt> - Flag to indicate whether
160 * to activate the URL Handlers service for the framework instance;
161 * the default value is "<tt>true</tt>". Activating the URL Handlers
162 * service will result in the <tt>URL.setURLStreamHandlerFactory()</tt>
163 * and <tt>URLConnection.setContentHandlerFactory()</tt> being called.
164 * </li>
Richard S. Hall930fecc2005-08-16 18:33:34 +0000165 * <li><tt>felix.embedded.execution</tt> - Flag to indicate whether
166 * the framework is embedded into a host application; the default value is
167 * "<tt>false</tt>". If this flag is "<tt>true</tt>" then the framework
168 * will not called <tt>System.exit()</tt> upon termination.
169 * </li>
170 * <li><tt>felix.strict.osgi</tt> - Flag to indicate whether the framework is
171 * running in strict OSGi mode; the default value is "<tt>true</tt>".
172 * If this flag is "<tt>false</tt>" it enables a non-OSGi-compliant
173 * feature by persisting <tt>BundleActivator</tt>s that implement
174 * <tt>Serializable</tt>. This feature is not recommended since
175 * it is non-compliant.
176 * </li>
177 * </ul>
178 * <p>
179 * Besides the above framework configuration properties, it is also
180 * possible to specify properties for the bundle cache. The available
181 * bundle cache properties depend on the cache implementation
182 * being used. For the properties of the default bundle cache, refer to the
183 * <a href="cache/DefaultBundleCache.html"><tt>DefaulBundleCache</tt></a>
184 * API documentation.
185 * </p>
186 * <p>
187 * Framework properties are somewhat misnamed, since they are not used by
188 * the framework, but by bundles via <tt>BundleContext.getProperty()</tt>.
189 * Please refer to bundle documentation of your specific bundle for any
190 * available properties.
191 * </p>
192 * <p>
193 * The <a href="Main.html"><tt>Main</tt></a> class implements some
194 * functionality for default property file handling, which makes it
195 * possible to specify configuration properties and framework properties
196 * in files that are automatically loaded when starting the framework. If you
197 * plan to create your own framework instance, you may be
198 * able to take advantage of the features it provides; refer to its
199 * class documentation for more information.
200 * </p>
201 *
Richard S. Hallea415752005-12-05 19:30:28 +0000202 * @param configMutable An object for obtaining configuration properties,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000203 * may be <tt>null</tt>.
204 * @param frameworkProps An object for obtaining framework properties,
205 * may be <tt>null</tt>.
206 * @param activatorList A list of System Bundle activators.
207 **/
208 public synchronized void start(
Richard S. Hallea415752005-12-05 19:30:28 +0000209 MutablePropertyResolver configMutable,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000210 List activatorList)
211 {
212 if (m_frameworkStatus != INITIAL_STATUS)
213 {
214 throw new IllegalStateException("Invalid framework status: " + m_frameworkStatus);
215 }
216
217 // The framework is now in its startup sequence.
218 m_frameworkStatus = STARTING_STATUS;
219
220 // Initialize member variables.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000221 m_factory = null;
Richard S. Hallea415752005-12-05 19:30:28 +0000222 m_configMutable = (configMutable == null)
223 ? new MutablePropertyResolverImpl(new StringMap(false)) : configMutable;
Richard S. Hall930fecc2005-08-16 18:33:34 +0000224 m_activeStartLevel = FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
225 m_installRequestMap = new HashMap();
226 m_installedBundleMap = new HashMap();
227 m_uninstalledBundles = null;
228 m_cache = null;
229 m_nextId = 1L;
230 m_dispatchQueue = null;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000231 m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000232 m_registry = new ServiceRegistry(m_logger);
233
234 // Add a listener to the service registry; this is
235 // used to distribute service registry events to
236 // service listeners.
237 m_registry.addServiceListener(new ServiceListener() {
238 public void serviceChanged(ServiceEvent event)
239 {
240 fireServiceEvent(event);
241 }
242 });
243
Richard S. Hall930fecc2005-08-16 18:33:34 +0000244 try
245 {
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000246 m_cache = new DefaultBundleCache(m_config, m_logger);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000247 }
248 catch (Exception ex)
249 {
250 System.err.println("Error creating bundle cache:");
251 ex.printStackTrace();
252
253 // Only shutdown the JVM if the framework is running stand-alone.
254 String embedded = m_config.get(
255 FelixConstants.EMBEDDED_EXECUTION_PROP);
256 boolean isEmbedded = (embedded == null)
257 ? false : embedded.equals("true");
258 if (!isEmbedded)
259 {
260 System.exit(-1);
261 }
262 else
263 {
264 throw new RuntimeException(ex.toString());
265 }
266 }
267
268 // Create search policy for module loader.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000269 m_policyCore = new R4SearchPolicyCore(m_logger);
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
326 // Initialize dispatch queue.
327 m_dispatchQueue = new FelixDispatchQueue(m_logger);
328
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. Hall29a4fbc2006-02-03 12:54:52 +0000342 systembundle.getInfo().addModule(m_factory.createModule("0"));
343 systembundle.getContentLoader().setSearchPolicy(
344 new R4SearchPolicy(
345 m_policyCore, systembundle.getInfo().getCurrentModule()));
346 m_factory.setContentLoader(
347 systembundle.getInfo().getCurrentModule(),
348 systembundle.getContentLoader());
349 m_policyCore.setExports(
350 systembundle.getInfo().getCurrentModule(), systembundle.getExports());
351
Richard S. Hall930fecc2005-08-16 18:33:34 +0000352 m_installedBundleMap.put(
353 systembundle.getInfo().getLocation(), systembundle);
354
355 // Manually resolve the System Bundle, which will cause its
356 // state to be set to RESOLVED.
357 try
358 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000359 m_policyCore.resolve(systembundle.getInfo().getCurrentModule());
Richard S. Hall930fecc2005-08-16 18:33:34 +0000360 }
361 catch (ResolveException ex)
362 {
363 // This should never happen.
364 throw new BundleException(
365 "Unresolved package in System Bundle:"
366 + ex.getPackage());
367 }
368
369 // Start the system bundle; this will set its state
370 // to STARTING, we must set its state to ACTIVE after
371 // all bundles are restarted below according to the spec.
372 systembundle.start();
373 }
374 catch (Exception ex)
375 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000376 m_factory = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +0000377 DispatchQueue.shutdown();
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000378 m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000379 throw new RuntimeException("Unable to start system bundle.");
380 }
381
382 // Reload and cached bundles.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000383 DefaultBundleArchive[] archives = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +0000384
385 // First get cached bundle identifiers.
386 try
387 {
388 archives = m_cache.getArchives();
389 }
390 catch (Exception ex)
391 {
392 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000393 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000394 "Unable to list saved bundles: " + ex, ex);
395 archives = null;
396 }
397
398 BundleImpl bundle = null;
399
400 // Now install all cached bundles.
401 for (int i = 0; (archives != null) && (i < archives.length); i++)
402 {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000403 try
404 {
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000405 // Make sure our id generator is not going to overlap.
406 // TODO: This is not correct since it may lead to re-used
407 // ids, which is not okay according to OSGi.
408 m_nextId = Math.max(m_nextId, archives[i].getId() + 1);
409
Richard S. Hall930fecc2005-08-16 18:33:34 +0000410 // It is possible that a bundle in the cache was previously
411 // uninstalled, but not completely deleted (perhaps because
412 // of a crash or a locked file), so if we see an archive
413 // with an UNINSTALLED persistent state, then try to remove
414 // it now.
415 if (archives[i].getPersistentState() == Bundle.UNINSTALLED)
416 {
417 m_cache.remove(archives[i]);
418 }
419 // Otherwise re-install the cached bundle.
420 else
421 {
422 // Install the cached bundle.
423 bundle = (BundleImpl) installBundle(
424 archives[i].getId(), archives[i].getLocation(), null);
425 }
426 }
427 catch (Exception ex)
428 {
429 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
430 try
431 {
432 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000433 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000434 "Unable to re-install " + archives[i].getLocation(),
435 ex);
436 }
437 catch (Exception ex2)
438 {
439 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000440 Logger.LOG_ERROR,
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000441 "Unable to re-install cached bundle.",
Richard S. Hall930fecc2005-08-16 18:33:34 +0000442 ex);
443 }
444 // TODO: Perhaps we should remove the cached bundle?
445 }
446 }
447
448 // Get the framework's default start level.
449 int startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
450 String s = m_config.get(FelixConstants.FRAMEWORK_STARTLEVEL_PROP);
451 if (s != null)
452 {
453 try
454 {
455 startLevel = Integer.parseInt(s);
456 }
457 catch (NumberFormatException ex)
458 {
459 startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
460 }
461 }
462
463 // Load bundles from auto-install and auto-start properties;
464 processAutoProperties();
465
Richard S. Hall17897152006-03-02 13:43:09 +0000466 // Set the start level using the start level service;
467 // this ensures that all start level requests are
468 // serialized.
469 // NOTE: There is potentially a specification compliance
470 // issue here, since the start level request is asynchronous;
471 // this means that the framework will fire its STARTED event
472 // before all bundles have officially been restarted and it
473 // is not clear if this is really an issue or not.
474 try
475 {
476 StartLevel sl = (StartLevel) getService(
477 getBundle(0),
478 getServiceReferences((BundleImpl) getBundle(0), StartLevel.class.getName(), null)[0]);
479 sl.setStartLevel(startLevel);
480 }
481 catch (InvalidSyntaxException ex)
482 {
483 // Should never happen.
484 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000485
486 // The framework is now running.
487 m_frameworkStatus = RUNNING_STATUS;
488
489 // Set the system bundle state to ACTIVE.
490 systembundle.getInfo().setState(Bundle.ACTIVE);
491
492 // Fire started event for system bundle.
493 fireBundleEvent(BundleEvent.STARTED, systembundle);
494
495 // Send a framework event to indicate the framework has started.
496 fireFrameworkEvent(FrameworkEvent.STARTED, getBundle(0), null);
497 }
498
499 /**
500 * This method cleanly shuts down the framework, it must be called at the
501 * end of a session in order to shutdown all active bundles.
502 **/
503 public synchronized void shutdown()
504 {
505 if (System.getSecurityManager() != null)
506 {
507 AccessController.checkPermission(m_adminPerm);
508 }
509
510 // Change framework status from running to stopping.
511 // If framework is not running, then just return.
512 if (m_frameworkStatus != RUNNING_STATUS)
513 {
514 return;
515 }
516
517 // The framework is now in its shutdown sequence.
518 m_frameworkStatus = STOPPING_STATUS;
519
Richard S. Hall17897152006-03-02 13:43:09 +0000520 // Use the start level service to set the start level to zero
521 // in order to stop all bundles in the framework. Since framework
522 // shutdown happens on its own thread, we can wait for the start
523 // level service to finish before proceeding by calling the
524 // non-spec setStartLevelAndWait() method.
525 try
526 {
527 StartLevelImpl sl = (StartLevelImpl) getService(
528 getBundle(0),
529 getServiceReferences((BundleImpl) getBundle(0), StartLevel.class.getName(), null)[0]);
530 sl.setStartLevelAndWait(0);
531 }
532 catch (InvalidSyntaxException ex)
533 {
534 // Should never happen.
535 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000536
537 // Just like initialize() called the system bundle's start()
538 // method, we must call its stop() method here so that it
539 // can perform any necessary clean up.
540 try
541 {
542 getBundle(0).stop();
543 }
544 catch (Exception ex)
545 {
546 fireFrameworkEvent(FrameworkEvent.ERROR, getBundle(0), ex);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000547 m_logger.log(Logger.LOG_ERROR, "Error stopping system bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000548 }
549
550 // Loop through all bundles and update any updated bundles.
551 Bundle[] bundles = getBundles();
552 for (int i = 0; i < bundles.length; i++)
553 {
554 BundleImpl bundle = (BundleImpl) bundles[i];
555 if (bundle.getInfo().isRemovalPending())
556 {
557 try
558 {
559 purgeBundle(bundle);
560 }
561 catch (Exception ex)
562 {
563 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000564 m_logger.log(Logger.LOG_ERROR, "Unable to purge bundle "
Richard S. Hall930fecc2005-08-16 18:33:34 +0000565 + bundle.getInfo().getLocation(), ex);
566 }
567 }
568 }
569
570 // Remove any uninstalled bundles.
571 for (int i = 0;
572 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
573 i++)
574 {
575 try
576 {
577 garbageCollectBundle(m_uninstalledBundles[i]);
578 }
579 catch (Exception ex)
580 {
581 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000582 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000583 "Unable to remove "
584 + m_uninstalledBundles[i].getInfo().getLocation(), ex);
585 }
586 }
587
588 // Shutdown event dispatching queue.
589 DispatchQueue.shutdown();
590
591 // The framework is no longer in a usable state.
592 m_frameworkStatus = INITIAL_STATUS;
593 }
594
595 public int getStatus()
596 {
597 return m_frameworkStatus;
598 }
599
600 /**
601 * Returns the active start level of the framework; this method
602 * implements functionality for the Start Level service.
603 * @return The active start level of the framework.
604 **/
605 protected int getStartLevel()
606 {
607 return m_activeStartLevel;
608 }
609
610 /**
611 * Implements the functionality of the <tt>setStartLevel()</tt>
612 * method for the StartLevel service, but does not do the security or
613 * parameter check. The security and parameter check are done in the
614 * StartLevel service implementation because this method is called on
615 * a separate thread and the caller's thread would already be gone if
Richard S. Hall17897152006-03-02 13:43:09 +0000616 * we did the checks in this method. This method should not be called
617 * directly.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000618 * @param requestedLevel The new start level of the framework.
619 **/
Richard S. Hall441c7152006-02-17 11:07:10 +0000620 protected void setFrameworkStartLevel(int requestedLevel)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000621 {
Richard S. Hall17897152006-03-02 13:43:09 +0000622 Bundle[] bundles = null;
623
624 // Synchronization for changing the start level is rather loose.
625 // The install lock is grabbed initially to atomically change the
626 // framework's start level and to grab a sorted snapshot of the
627 // currently installed bundles, but then this lock is freed immediately.
628 // No locks are held while processing the currently installed bundles
629 // for starting/stopping based on the new start level. The only locking
630 // that occurs is for individual bundles when startBundle()/stopBundle()
631 // is called, but this locking is done in the respective method.
632 //
633 // This approach does mean that it is possible for a for individual
634 // bundle states to change during this operation. For example, bundle
635 // start levels can be changed or bundles can be uninstalled. If a
636 // bundle's start level changes, then it is possible for it to be
637 // processed out of order. Uninstalled bundles are just logged and
638 // ignored. I had a bit of discussion with Peter Kriens about these
639 // issues and he felt they were consistent with the spec, which
640 // intended Start Level to have some leeway.
641 //
642 // Calls to this method are only made by the start level thread, which
643 // serializes framework start level changes. Thus, it is not possible
644 // for two requests to change the framework's start level to interfere
645 // with each other.
646
647 synchronized (m_installedBundleLock_Priority2)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000648 {
Richard S. Hall17897152006-03-02 13:43:09 +0000649 // Determine if we are lowering or raising the
650 // active start level.
651 boolean lowering = (requestedLevel < m_activeStartLevel);
652
653 // Record new start level.
654 m_activeStartLevel = requestedLevel;
655
656 // Get a snapshot of all installed bundles.
657 bundles = getBundles();
658
659 // Sort bundle array by start level either ascending or
660 // descending depending on whether the start level is being
661 // lowered or raised to that the bundles can be efficiently
662 // processed in order.
663 Comparator comparator = null;
664 if (lowering)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000665 {
Richard S. Hall17897152006-03-02 13:43:09 +0000666 // Sort descending to stop highest start level first.
667 comparator = new Comparator() {
668 public int compare(Object o1, Object o2)
Richard S. Hall441c7152006-02-17 11:07:10 +0000669 {
Richard S. Hall17897152006-03-02 13:43:09 +0000670 BundleImpl b1 = (BundleImpl) o1;
671 BundleImpl b2 = (BundleImpl) o2;
672 if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
673 < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
674 {
675 return 1;
676 }
677 else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
678 > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
679 {
680 return -1;
681 }
682 return 0;
Richard S. Hall441c7152006-02-17 11:07:10 +0000683 }
Richard S. Hall17897152006-03-02 13:43:09 +0000684 };
685 }
686 else
687 {
688 // Sort ascending to start lowest 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()))
Richard S. Hall441c7152006-02-17 11:07:10 +0000696 {
Richard S. Hall17897152006-03-02 13:43:09 +0000697 return 1;
Richard S. Hall441c7152006-02-17 11:07:10 +0000698 }
Richard S. Hall17897152006-03-02 13:43:09 +0000699 else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
700 < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
Richard S. Hall441c7152006-02-17 11:07:10 +0000701 {
Richard S. Hall17897152006-03-02 13:43:09 +0000702 return -1;
Richard S. Hall441c7152006-02-17 11:07:10 +0000703 }
Richard S. Hall17897152006-03-02 13:43:09 +0000704 return 0;
705 }
706 };
707 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000708
Richard S. Hall17897152006-03-02 13:43:09 +0000709 Arrays.sort(bundles, comparator);
710 }
711
712 // Stop or start the bundles according to the start level.
713 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
714 {
715 BundleImpl impl = (BundleImpl) bundles[i];
716
717 // Ignore the system bundle, since its start() and
718 // stop() methods get called explicitly in Felix.start()
719 // and Felix.shutdown(), respectively.
720 if (impl.getInfo().getBundleId() == 0)
721 {
722 continue;
723 }
724
725 // Lock the current bundle.
726 acquireBundleLock(impl);
727
728 try
729 {
730 // Start the bundle if necessary.
731 if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
732 (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
733 <= m_activeStartLevel))
734 {
735 try
736 {
737 startBundle(impl, false);
738 }
739 catch (Throwable th)
740 {
741 fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
742 m_logger.log(
743 Logger.LOG_ERROR,
744 "Error starting " + impl.getInfo().getLocation(), th);
Richard S. Hall441c7152006-02-17 11:07:10 +0000745 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000746 }
Richard S. Hall17897152006-03-02 13:43:09 +0000747 // Stop the bundle if necessary.
748 else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
749 > m_activeStartLevel)
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000750 {
Richard S. Hall17897152006-03-02 13:43:09 +0000751 try
Richard S. Hall441c7152006-02-17 11:07:10 +0000752 {
Richard S. Hall17897152006-03-02 13:43:09 +0000753 stopBundle(impl, false);
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000754 }
Richard S. Hall17897152006-03-02 13:43:09 +0000755 catch (Throwable th)
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000756 {
Richard S. Hall17897152006-03-02 13:43:09 +0000757 fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
758 m_logger.log(
759 Logger.LOG_ERROR,
760 "Error stopping " + impl.getInfo().getLocation(), th);
Richard S. Hall441c7152006-02-17 11:07:10 +0000761 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000762 }
Richard S. Hall17897152006-03-02 13:43:09 +0000763 }
764 finally
765 {
766 // Always release bundle lock.
767 releaseBundleLock(impl);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000768 }
769 }
770
771 fireFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, getBundle(0), null);
772 }
773
774 /**
775 * Returns the start level into which newly installed bundles will
776 * be placed by default; this method implements functionality for
777 * the Start Level service.
778 * @return The default start level for newly installed bundles.
779 **/
780 protected int getInitialBundleStartLevel()
781 {
782 String s = m_config.get(FelixConstants.BUNDLE_STARTLEVEL_PROP);
783
784 if (s != null)
785 {
786 try
787 {
788 int i = Integer.parseInt(s);
789 return (i > 0) ? i : FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
790 }
791 catch (NumberFormatException ex)
792 {
793 // Ignore and return the default value.
794 }
795 }
796 return FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
797 }
798
799 /**
800 * Sets the default start level into which newly installed bundles
801 * will be placed; this method implements functionality for the Start
802 * Level service.
803 * @param startLevel The new default start level for newly installed
804 * bundles.
805 * @throws java.lang.IllegalArgumentException If the specified start
806 * level is not greater than zero.
807 * @throws java.security.SecurityException If the caller does not
808 * have <tt>AdminPermission</tt>.
809 **/
810 protected void setInitialBundleStartLevel(int startLevel)
811 {
812 if (System.getSecurityManager() != null)
813 {
814 AccessController.checkPermission(m_adminPerm);
815 }
816
817 if (startLevel <= 0)
818 {
819 throw new IllegalArgumentException(
820 "Initial start level must be greater than zero.");
821 }
822
Richard S. Hallea415752005-12-05 19:30:28 +0000823 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +0000824 FelixConstants.BUNDLE_STARTLEVEL_PROP, Integer.toString(startLevel));
825 }
826
827 /**
828 * Returns the start level for the specified bundle; this method
829 * implements functionality for the Start Level service.
830 * @param bundle The bundle to examine.
831 * @return The start level of the specified bundle.
832 * @throws java.lang.IllegalArgumentException If the specified
833 * bundle has been uninstalled.
834 **/
835 protected int getBundleStartLevel(Bundle bundle)
836 {
837 if (bundle.getState() == Bundle.UNINSTALLED)
838 {
839 throw new IllegalArgumentException("Bundle is uninstalled.");
840 }
841
842 return ((BundleImpl) bundle).getInfo().getStartLevel(getInitialBundleStartLevel());
843 }
844
845 /**
846 * Sets the start level of the specified bundle; this method
847 * implements functionality for the Start Level service.
848 * @param bundle The bundle whose start level is to be modified.
849 * @param startLevel The new start level of the specified bundle.
850 * @throws java.lang.IllegalArgumentException If the specified
851 * bundle is the system bundle or if the bundle has been
852 * uninstalled.
853 * @throws java.security.SecurityException If the caller does not
854 * have <tt>AdminPermission</tt>.
855 **/
856 protected void setBundleStartLevel(Bundle bundle, int startLevel)
857 {
858 if (System.getSecurityManager() != null)
859 {
860 AccessController.checkPermission(m_adminPerm);
861 }
862
863 // Cannot change the system bundle.
864 if (bundle.getBundleId() == 0)
865 {
866 throw new IllegalArgumentException(
867 "Cannot change system bundle start level.");
868 }
869
870 // Acquire bundle lock.
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000871 acquireBundleLock((BundleImpl) bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000872
873 Throwable rethrow = null;
874
875 try
876 {
877 if (bundle.getState() == Bundle.UNINSTALLED)
878 {
879 throw new IllegalArgumentException("Bundle is uninstalled.");
880 }
881
882 if (startLevel >= 1)
883 {
884 BundleImpl impl = (BundleImpl) bundle;
885 impl.getInfo().setStartLevel(startLevel);
886
887 try
888 {
889 // Start the bundle if necessary.
890 if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
891 (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
892 <= m_activeStartLevel))
893 {
894 startBundle(impl, false);
895 }
896 // Stop the bundle if necessary.
897 else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
898 > m_activeStartLevel)
899 {
900 stopBundle(impl, false);
901 }
902 }
903 catch (Throwable th)
904 {
905 rethrow = th;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000906 m_logger.log(Logger.LOG_ERROR, "Error starting/stopping bundle.", th);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000907 }
908 }
909 else
910 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000911 m_logger.log(Logger.LOG_WARNING, "Bundle start level must be greater than zero.");
Richard S. Hall930fecc2005-08-16 18:33:34 +0000912 }
913 }
914 finally
915 {
916 // Always release bundle lock.
917 releaseBundleLock((BundleImpl) bundle);
918 }
919
920 if (rethrow != null)
921 {
922 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, rethrow);
923 }
924 }
925
926 /**
927 * Returns whether a bundle is persistently started; this is an
928 * method implementation for the Start Level service.
929 * @param bundle The bundle to examine.
930 * @return <tt>true</tt> if the bundle is marked as persistently
931 * started, <tt>false</tt> otherwise.
932 * @throws java.lang.IllegalArgumentException If the specified
933 * bundle has been uninstalled.
934 **/
935 protected boolean isBundlePersistentlyStarted(Bundle bundle)
936 {
937 if (bundle.getState() == Bundle.UNINSTALLED)
938 {
939 throw new IllegalArgumentException("Bundle is uninstalled.");
940 }
941
942 return (((BundleImpl) bundle).getInfo().getPersistentState() == Bundle.ACTIVE);
943 }
944
Richard S. Hall5d226732005-11-08 09:09:05 +0000945 /**
946 * <p>
947 * This method is used to determine if the specified class is from
948 * a bundle installed in the framework instance. This method is used
949 * by the URL Handlers service when determining the framework instance
950 * associated with call stack.
951 * </p>
952 * @param clazz The class to test for whether it comes from a bundle.
953 * @return <tt>true</tt> if the class comes from a bundle installed in
954 * the framework, <tt>false</tt> otherwise.
955 **/
956 protected boolean isBundleClass(Class clazz)
957 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000958 if (clazz.getClassLoader() instanceof ContentClassLoader)
Richard S. Hall5d226732005-11-08 09:09:05 +0000959 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000960 IContentLoader contentLoader =
961 ((ContentClassLoader) clazz.getClassLoader()).getContentLoader();
962 IModule[] modules = m_factory.getModules();
963 for (int i = 0; i < modules.length; i++)
964 {
965 if (modules[i].getContentLoader() == contentLoader)
966 {
967 return true;
968 }
969 }
Richard S. Hall5d226732005-11-08 09:09:05 +0000970 }
971 return false;
972 }
973
Richard S. Hall930fecc2005-08-16 18:33:34 +0000974 //
975 // Implementation of Bundle interface methods.
976 //
977
978 /**
979 * Implementation for Bundle.getHeaders().
980 **/
981 protected Dictionary getBundleHeaders(BundleImpl bundle)
982 {
983 if (System.getSecurityManager() != null)
984 {
985 AccessController.checkPermission(m_adminPerm);
986 }
987 return new MapToDictionary(bundle.getInfo().getCurrentHeader());
988 }
989
990 /**
991 * Implementation for Bundle.getLocation().
992 **/
993 protected String getBundleLocation(BundleImpl bundle)
994 {
995 if (System.getSecurityManager() != null)
996 {
997 AccessController.checkPermission(m_adminPerm);
998 }
999 return bundle.getInfo().getLocation();
1000 }
1001
1002 /**
1003 * Implementation for Bundle.getResource().
1004 **/
1005 protected URL getBundleResource(BundleImpl bundle, String name)
1006 {
1007 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1008 {
1009 throw new IllegalStateException("The bundle is uninstalled.");
1010 }
1011 else if (System.getSecurityManager() != null)
1012 {
Richard S. Hall5d7a94a2006-02-06 12:57:30 +00001013 try
1014 {
1015 AccessController.checkPermission(
1016 new AdminPermission(bundle, AdminPermission.RESOURCE));
1017 }
1018 catch (SecurityException ex)
1019 {
1020 // Spec says to return null if there is a security exception.
1021 return null;
1022 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001023 }
Richard S. Hall001cc302006-02-03 15:03:24 +00001024 return bundle.getInfo().getCurrentModule().getResource(name);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001025 }
1026
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001027 /**
1028 * Implementation for Bundle.getEntry().
1029 **/
1030 protected URL getBundleEntry(BundleImpl bundle, String name)
1031 {
1032 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1033 {
1034 throw new IllegalStateException("The bundle is uninstalled.");
1035 }
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001036 else if (System.getSecurityManager() != null)
1037 {
Richard S. Hall5d7a94a2006-02-06 12:57:30 +00001038 try
1039 {
1040 AccessController.checkPermission(
1041 new AdminPermission(bundle, AdminPermission.RESOURCE));
1042 }
1043 catch (SecurityException ex)
1044 {
1045 // Spec says to return null if there is a security exception.
1046 return null;
1047 }
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001048 }
1049 return ((ContentLoaderImpl) bundle.getInfo().getCurrentModule()
1050 .getContentLoader()).getResourceFromContent(name);
1051 }
1052
Richard S. Hall4f09b642006-02-06 10:59:19 +00001053 /**
1054 * Implementation for Bundle.getEntryPaths().
1055 **/
1056 protected Enumeration getBundleEntryPaths(BundleImpl bundle, String path)
1057 {
1058 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1059 {
1060 throw new IllegalStateException("The bundle is uninstalled.");
1061 }
Richard S. Hall4f09b642006-02-06 10:59:19 +00001062 else if (System.getSecurityManager() != null)
1063 {
Richard S. Hall5d7a94a2006-02-06 12:57:30 +00001064 try
1065 {
1066 AccessController.checkPermission(
1067 new AdminPermission(bundle, AdminPermission.RESOURCE));
1068 }
1069 catch (SecurityException ex)
1070 {
1071 // Spec says to return null if there is a security exception.
1072 return null;
1073 }
Richard S. Hall4f09b642006-02-06 10:59:19 +00001074 }
1075 // Strip leading '/' if present.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001076 if ((path.length() > 0) && (path.charAt(0) == '/'))
Richard S. Hall4f09b642006-02-06 10:59:19 +00001077 {
1078 path = path.substring(1);
1079 }
1080 return bundle.getInfo().getCurrentModule()
1081 .getContentLoader().getContent().getEntryPaths(path);
1082 }
1083
Richard S. Hall930fecc2005-08-16 18:33:34 +00001084 protected ServiceReference[] getBundleRegisteredServices(BundleImpl bundle)
1085 {
1086 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1087 {
1088 throw new IllegalStateException("The bundle is uninstalled.");
1089 }
1090
1091 // Filter list of registered service references.
1092 ServiceReference[] refs = m_registry.getRegisteredServices(bundle);
1093 List list = new ArrayList();
1094 for (int refIdx = 0; (refs != null) && (refIdx < refs.length); refIdx++)
1095 {
1096 // Check that the current security context has permission
1097 // to get at least one of the service interfaces; the
1098 // objectClass property of the service stores its service
1099 // interfaces.
1100 boolean hasPermission = false;
1101 if (System.getSecurityManager() != null)
1102 {
1103 String[] objectClass = (String[])
1104 refs[refIdx].getProperty(Constants.OBJECTCLASS);
1105 if (objectClass == null)
1106 {
1107 return null;
1108 }
1109 for (int ifcIdx = 0;
1110 !hasPermission && (ifcIdx < objectClass.length);
1111 ifcIdx++)
1112 {
1113 try
1114 {
1115 ServicePermission perm =
1116 new ServicePermission(
1117 objectClass[ifcIdx], ServicePermission.GET);
1118 AccessController.checkPermission(perm);
1119 hasPermission = true;
1120 }
1121 catch (Exception ex)
1122 {
1123 }
1124 }
1125 }
1126 else
1127 {
1128 hasPermission = true;
1129 }
1130
1131 if (hasPermission)
1132 {
1133 list.add(refs[refIdx]);
1134 }
1135 }
1136
1137 if (list.size() > 0)
1138 {
1139 return (ServiceReference[])
1140 list.toArray(new ServiceReference[list.size()]);
1141 }
1142
1143 return null;
1144 }
1145
1146 protected ServiceReference[] getBundleServicesInUse(Bundle bundle)
1147 {
1148 // Filter list of "in use" service references.
1149 ServiceReference[] refs = m_registry.getServicesInUse(bundle);
1150 List list = new ArrayList();
1151 for (int refIdx = 0; (refs != null) && (refIdx < refs.length); refIdx++)
1152 {
1153 // Check that the current security context has permission
1154 // to get at least one of the service interfaces; the
1155 // objectClass property of the service stores its service
1156 // interfaces.
1157 boolean hasPermission = false;
1158 if (System.getSecurityManager() != null)
1159 {
1160 String[] objectClass = (String[])
1161 refs[refIdx].getProperty(Constants.OBJECTCLASS);
1162 if (objectClass == null)
1163 {
1164 return null;
1165 }
1166 for (int ifcIdx = 0;
1167 !hasPermission && (ifcIdx < objectClass.length);
1168 ifcIdx++)
1169 {
1170 try
1171 {
1172 ServicePermission perm =
1173 new ServicePermission(
1174 objectClass[ifcIdx], ServicePermission.GET);
1175 AccessController.checkPermission(perm);
1176 hasPermission = true;
1177 }
1178 catch (Exception ex)
1179 {
1180 }
1181 }
1182 }
1183 else
1184 {
1185 hasPermission = true;
1186 }
1187
1188 if (hasPermission)
1189 {
1190 list.add(refs[refIdx]);
1191 }
1192 }
1193
1194 if (list.size() > 0)
1195 {
1196 return (ServiceReference[])
1197 list.toArray(new ServiceReference[list.size()]);
1198 }
1199
1200 return null;
1201 }
1202
1203 protected boolean bundleHasPermission(BundleImpl bundle, Object obj)
1204 {
1205 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1206 {
1207 throw new IllegalStateException("The bundle is uninstalled.");
1208 }
1209
Richard S. Hall2cf44c92006-01-23 19:23:56 +00001210 if (System.getSecurityManager() != null)
Richard S. Hall65730962006-01-23 19:23:13 +00001211 {
1212 try
1213 {
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001214 return (obj instanceof java.security.Permission)
1215 ? java.security.Policy.getPolicy().getPermissions(
Richard S. Hall65730962006-01-23 19:23:13 +00001216 new java.security.CodeSource(
Richard S. Hallc762b692006-01-27 15:18:57 +00001217 new java.net.URL(bundle.getInfo().getLocation()),
1218 (java.security.cert.Certificate[]) null))
Richard S. Hall65730962006-01-23 19:23:13 +00001219 .implies((java.security.Permission) obj)
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001220 : false;
Richard S. Hall65730962006-01-23 19:23:13 +00001221 }
1222 catch (Exception ex)
1223 {
1224 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001225 Logger.LOG_WARNING,
Richard S. Hall65730962006-01-23 19:23:13 +00001226 "Exception while evaluating the permission.",
1227 ex);
1228 return false;
1229 }
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001230 }
Richard S. Hall65730962006-01-23 19:23:13 +00001231
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001232 return true;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001233 }
1234
1235 /**
Richard S. Hall74b97972005-11-30 15:51:41 +00001236 * Implementation for Bundle.loadClass().
1237 **/
1238 protected Class loadBundleClass(BundleImpl bundle, String name) throws ClassNotFoundException
1239 {
Richard S. Hallf1359482006-02-14 08:02:51 +00001240 Class clazz = bundle.getInfo().getCurrentModule().getClass(name);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001241 if (clazz == null)
Richard S. Hall74b97972005-11-30 15:51:41 +00001242 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001243 // Throw exception.
1244 ClassNotFoundException ex = new ClassNotFoundException(name);
1245
Richard S. Hall624f8012005-11-30 15:53:43 +00001246 // The spec says we must fire a framework error.
Richard S. Hall74b97972005-11-30 15:51:41 +00001247 fireFrameworkEvent(
1248 FrameworkEvent.ERROR, bundle,
1249 new BundleException(ex.getMessage()));
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001250
Richard S. Hall74b97972005-11-30 15:51:41 +00001251 throw ex;
1252 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001253 return clazz;
Richard S. Hall74b97972005-11-30 15:51:41 +00001254 }
1255
1256 /**
Richard S. Hall930fecc2005-08-16 18:33:34 +00001257 * Implementation for Bundle.start().
1258 **/
1259 protected void startBundle(BundleImpl bundle, boolean record)
1260 throws BundleException
1261 {
1262 if (System.getSecurityManager() != null)
1263 {
1264 AccessController.checkPermission(m_adminPerm);
1265 }
1266
1267 // CONCURRENCY NOTE:
1268 // Starting a bundle may actually impact many bundles, since
1269 // the bundle being started my need to be resolved, which in
1270 // turn may need to resolve other bundles. Despite this fact,
1271 // we only acquire the lock for the bundle being started, because
1272 // when resolve is called on this bundle, it will eventually
1273 // call resolve on the module loader search policy, which does
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001274 // its own locking on the module factory instance. Since the
1275 // resolve algorithm is locking the module factory instance, it
Richard S. Hall930fecc2005-08-16 18:33:34 +00001276 // is not possible for other bundles to be installed or removed,
1277 // so we don't have to worry about these possibilities.
1278 //
1279 // Further, if other bundles are started during this operation,
1280 // then either they will resolve first because they got the lock
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001281 // on the module factory or we will resolve first since we got
1282 // the lock on the module factory, so there should be no interference.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001283 // If other bundles are stopped or uninstalled, this should pose
1284 // no problems, since this does not impact their resolved state.
1285 // If a refresh occurs, then the refresh algorithm ulimately has
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001286 // to acquire the module factory instance lock too before it can
Richard S. Hall930fecc2005-08-16 18:33:34 +00001287 // completely purge old modules, so it should also complete either
1288 // before or after this bundle is started. At least that's the
1289 // theory.
1290
1291 // Acquire bundle lock.
1292 acquireBundleLock(bundle);
1293
1294 try
1295 {
1296 _startBundle(bundle, record);
1297 }
1298 finally
1299 {
1300 // Release bundle lock.
1301 releaseBundleLock(bundle);
1302 }
1303 }
1304
1305 private void _startBundle(BundleImpl bundle, boolean record)
1306 throws BundleException
1307 {
1308 // Set and save the bundle's persistent state to active
1309 // if we are supposed to record state change.
1310 if (record)
1311 {
1312 bundle.getInfo().setPersistentStateActive();
1313 }
1314
1315 // Try to start the bundle.
1316 BundleInfo info = bundle.getInfo();
1317
1318 // Ignore bundles whose persistent state is not active
1319 // or whose start level is greater than the framework's.
1320 if ((info.getPersistentState() != Bundle.ACTIVE)
1321 || (info.getStartLevel(getInitialBundleStartLevel()) > getStartLevel()))
1322 {
1323 return;
1324 }
1325
1326 switch (info.getState())
1327 {
1328 case Bundle.UNINSTALLED:
1329 throw new IllegalStateException("Cannot start an uninstalled bundle.");
1330 case Bundle.STARTING:
1331 case Bundle.STOPPING:
1332 throw new BundleException("Starting a bundle that is starting or stopping is currently not supported.");
1333 case Bundle.ACTIVE:
1334 return;
1335 case Bundle.INSTALLED:
1336 _resolveBundle(bundle);
1337 case Bundle.RESOLVED:
1338 info.setState(Bundle.STARTING);
1339 }
1340
1341 try
1342 {
1343 // Set the bundle's activator.
1344 bundle.getInfo().setActivator(createBundleActivator(bundle.getInfo()));
1345
1346 // Activate the bundle if it has an activator.
1347 if (bundle.getInfo().getActivator() != null)
1348 {
1349 if (info.getContext() == null)
1350 {
1351 info.setContext(new BundleContextImpl(this, bundle));
1352 }
1353
1354 if (System.getSecurityManager() != null)
1355 {
1356// m_startStopPrivileged.setAction(StartStopPrivileged.START_ACTION);
1357// m_startStopPrivileged.setBundle(bundle);
1358// AccessController.doPrivileged(m_startStopPrivileged);
1359 }
1360 else
1361 {
1362 info.getActivator().start(info.getContext());
1363 }
1364 }
1365
1366 info.setState(Bundle.ACTIVE);
1367
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001368 // TODO: CONCURRENCY - Reconsider firing event outside of the
1369 // bundle lock.
1370
Richard S. Hall930fecc2005-08-16 18:33:34 +00001371 fireBundleEvent(BundleEvent.STARTED, bundle);
1372 }
1373 catch (Throwable th)
1374 {
1375 // If there was an error starting the bundle,
1376 // then reset its state to RESOLVED.
1377 info.setState(Bundle.RESOLVED);
1378
1379 // Unregister any services offered by this bundle.
1380 m_registry.unregisterServices(bundle);
1381
1382 // Release any services being used by this bundle.
1383 m_registry.ungetServices(bundle);
1384
1385 // Remove any listeners registered by this bundle.
1386 removeListeners(bundle);
1387
1388 // The spec says to expect BundleException or
1389 // SecurityException, so rethrow these exceptions.
1390 if (th instanceof BundleException)
1391 {
1392 throw (BundleException) th;
1393 }
1394 else if (th instanceof SecurityException)
1395 {
1396 throw (SecurityException) th;
1397 }
1398 // Convert a privileged action exception to the
1399 // nested exception.
1400 else if (th instanceof PrivilegedActionException)
1401 {
1402 th = ((PrivilegedActionException) th).getException();
1403 }
1404
1405 // Rethrow all other exceptions as a BundleException.
1406 throw new BundleException("Activator start error.", th);
1407 }
1408 }
1409
1410 protected void _resolveBundle(BundleImpl bundle)
1411 throws BundleException
1412 {
1413 // If a security manager is installed, then check for permission
1414 // to import the necessary packages.
1415 if (System.getSecurityManager() != null)
1416 {
1417 URL url = null;
1418 try
1419 {
1420 url = new URL(bundle.getInfo().getLocation());
1421 }
1422 catch (MalformedURLException ex)
1423 {
1424 throw new BundleException("Cannot resolve, bad URL "
1425 + bundle.getInfo().getLocation());
1426 }
1427
1428// try
1429// {
1430// AccessController.doPrivileged(new CheckImportsPrivileged(url, bundle));
1431// }
1432// catch (PrivilegedActionException ex)
1433// {
1434// Exception thrown = ((PrivilegedActionException) ex).getException();
1435// if (thrown instanceof AccessControlException)
1436// {
1437// throw (AccessControlException) thrown;
1438// }
1439// else
1440// {
1441// throw new BundleException("Problem resolving: " + ex);
1442// }
1443// }
1444 }
1445
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001446 IModule module = bundle.getInfo().getCurrentModule();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001447 try
1448 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001449 m_policyCore.resolve(module);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001450 }
1451 catch (ResolveException ex)
1452 {
1453 if (ex.getModule() != null)
1454 {
1455 throw new BundleException(
1456 "Unresolved package in bundle "
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001457 + Util.getBundleIdFromModuleId(ex.getModule().getId())
Richard S. Hall930fecc2005-08-16 18:33:34 +00001458 + ": " + ex.getPackage());
1459 }
1460 else
1461 {
1462 throw new BundleException(ex.getMessage());
1463 }
1464 }
1465
1466 bundle.getInfo().setState(Bundle.RESOLVED);
1467 }
1468
1469 protected void updateBundle(BundleImpl bundle, InputStream is)
1470 throws BundleException
1471 {
1472 if (System.getSecurityManager() != null)
1473 {
1474 AccessController.checkPermission(m_adminPerm);
1475 }
1476
1477 // Acquire bundle lock.
1478 acquireBundleLock(bundle);
1479
1480 try
1481 {
1482 _updateBundle(bundle, is);
1483 }
1484 finally
1485 {
1486 // Release bundle lock.
1487 releaseBundleLock(bundle);
1488 }
1489 }
1490
1491 protected void _updateBundle(BundleImpl bundle, InputStream is)
1492 throws BundleException
1493 {
1494 // We guarantee to close the input stream, so put it in a
1495 // finally clause.
1496
1497 try
1498 {
1499 // Variable to indicate whether bundle is active or not.
1500 Exception rethrow = null;
1501
1502 // Cannot update an uninstalled bundle.
1503 BundleInfo info = bundle.getInfo();
1504 if (info.getState() == Bundle.UNINSTALLED)
1505 {
1506 throw new IllegalStateException("The bundle is uninstalled.");
1507 }
1508
1509 // First get the update-URL from our header.
1510 String updateLocation = (String)
1511 info.getCurrentHeader().get(Constants.BUNDLE_UPDATELOCATION);
1512
1513 // If no update location specified, use original location.
1514 if (updateLocation == null)
1515 {
1516 updateLocation = info.getLocation();
1517 }
1518
1519 // Stop the bundle, but do not change the persistent state.
1520 stopBundle(bundle, false);
1521
1522 try
1523 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001524 // Get the bundle's archive.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001525 DefaultBundleArchive archive = m_cache.getArchive(info.getBundleId());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001526 // Update the bundle; this operation will increase
1527 // the revision count for the bundle.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001528 archive.revise(updateLocation, is);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001529 // Create a module for the new revision; the revision is
1530 // base zero, so subtract one from the revision count to
1531 // get the revision of the new update.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001532 IModule module = createModule(
Richard S. Hall930fecc2005-08-16 18:33:34 +00001533 info.getBundleId(),
1534 archive.getRevisionCount() - 1,
1535 info.getCurrentHeader());
1536 // Add module to bundle info.
1537 info.addModule(module);
1538 }
1539 catch (Exception ex)
1540 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001541 m_logger.log(Logger.LOG_ERROR, "Unable to update the bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001542 rethrow = ex;
1543 }
1544
1545 info.setState(Bundle.INSTALLED);
Richard S. Hall69d84792006-01-13 13:55:13 +00001546 info.setLastModified(System.currentTimeMillis());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001547
1548 // Mark as needing a refresh.
1549 info.setRemovalPending();
1550
1551 // Fire updated event if successful.
1552 if (rethrow == null)
1553 {
1554 fireBundleEvent(BundleEvent.UPDATED, bundle);
1555 }
1556
1557 // Restart bundle, but do not change the persistent state.
1558 // This will not start the bundle if it was not previously
1559 // active.
1560 startBundle(bundle, false);
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001561
Richard S. Hall930fecc2005-08-16 18:33:34 +00001562 // If update failed, rethrow exception.
1563 if (rethrow != null)
1564 {
1565 throw new BundleException("Update failed.", rethrow);
1566 }
1567 }
1568 finally
1569 {
1570 try
1571 {
1572 if (is != null) is.close();
1573 }
1574 catch (IOException ex)
1575 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001576 m_logger.log(Logger.LOG_ERROR, "Unable to close input stream.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001577 }
1578 }
1579 }
1580
1581 protected void stopBundle(BundleImpl bundle, boolean record)
1582 throws BundleException
1583 {
1584 if (System.getSecurityManager() != null)
1585 {
1586 AccessController.checkPermission(m_adminPerm);
1587 }
1588
1589 // Acquire bundle lock.
1590 acquireBundleLock(bundle);
1591
1592 try
1593 {
1594 _stopBundle(bundle, record);
1595 }
1596 finally
1597 {
1598 // Always release bundle lock.
1599 releaseBundleLock(bundle);
1600 }
1601 }
1602
1603 private void _stopBundle(BundleImpl bundle, boolean record)
1604 throws BundleException
1605 {
1606 Throwable rethrow = null;
1607
1608 // Set the bundle's persistent state to inactive if necessary.
1609 if (record)
1610 {
1611 bundle.getInfo().setPersistentStateInactive();
1612 }
1613
1614 BundleInfo info = bundle.getInfo();
1615
1616 switch (info.getState())
1617 {
1618 case Bundle.UNINSTALLED:
1619 throw new IllegalStateException("Cannot stop an uninstalled bundle.");
1620 case Bundle.STARTING:
1621 case Bundle.STOPPING:
1622 throw new BundleException("Stopping a bundle that is starting or stopping is currently not supported.");
1623 case Bundle.INSTALLED:
1624 case Bundle.RESOLVED:
1625 return;
1626 case Bundle.ACTIVE:
1627 // Set bundle state..
1628 info.setState(Bundle.STOPPING);
1629 }
1630
1631 try
1632 {
1633 if (bundle.getInfo().getActivator() != null)
1634 {
1635 if (System.getSecurityManager() != null)
1636 {
1637// m_startStopPrivileged.setAction(StartStopPrivileged.STOP_ACTION);
1638// m_startStopPrivileged.setBundle(bundle);
1639// AccessController.doPrivileged(m_startStopPrivileged);
1640 }
1641 else
1642 {
1643 info.getActivator().stop(info.getContext());
1644 }
1645 }
1646
1647 // Try to save the activator in the cache.
1648 // NOTE: This is non-standard OSGi behavior and only
1649 // occurs if strictness is disabled.
1650 String strict = m_config.get(FelixConstants.STRICT_OSGI_PROP);
1651 boolean isStrict = (strict == null) ? true : strict.equals("true");
1652 if (!isStrict)
1653 {
1654 try
1655 {
1656 m_cache.getArchive(info.getBundleId())
1657 .setActivator(info.getActivator());
1658 }
1659 catch (Exception ex)
1660 {
1661 // Problem saving activator, so ignore it.
1662 // TODO: Perhaps we should handle this some other way?
1663 }
1664 }
1665 }
1666 catch (Throwable th)
1667 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001668 m_logger.log(Logger.LOG_ERROR, "Error stopping bundle.", th);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001669 rethrow = th;
1670 }
1671
1672 // Unregister any services offered by this bundle.
1673 m_registry.unregisterServices(bundle);
1674
1675 // Release any services being used by this bundle.
1676 m_registry.ungetServices(bundle);
1677
1678 // The spec says that we must remove all event
1679 // listeners for a bundle when it is stopped.
1680 removeListeners(bundle);
1681
1682 info.setState(Bundle.RESOLVED);
1683 fireBundleEvent(BundleEvent.STOPPED, bundle);
1684
1685 // Throw activator error if there was one.
1686 if (rethrow != null)
1687 {
1688 // The spec says to expect BundleException or
1689 // SecurityException, so rethrow these exceptions.
1690 if (rethrow instanceof BundleException)
1691 {
1692 throw (BundleException) rethrow;
1693 }
1694 else if (rethrow instanceof SecurityException)
1695 {
1696 throw (SecurityException) rethrow;
1697 }
1698 else if (rethrow instanceof PrivilegedActionException)
1699 {
1700 rethrow = ((PrivilegedActionException) rethrow).getException();
1701 }
1702
1703 // Rethrow all other exceptions as a BundleException.
1704 throw new BundleException("Activator stop error.", rethrow);
1705 }
1706 }
1707
1708 protected void uninstallBundle(BundleImpl bundle) throws BundleException
1709 {
1710 if (System.getSecurityManager() != null)
1711 {
1712 AccessController.checkPermission(m_adminPerm);
1713 }
1714
1715 // Acquire bundle lock.
1716 acquireBundleLock(bundle);
1717
1718 try
1719 {
1720 _uninstallBundle(bundle);
1721 }
1722 finally
1723 {
1724 // Always release bundle lock.
1725 releaseBundleLock(bundle);
1726 }
1727 }
1728
1729 private void _uninstallBundle(BundleImpl bundle) throws BundleException
1730 {
1731 if (System.getSecurityManager() != null)
1732 {
1733 AccessController.checkPermission(m_adminPerm);
1734 }
1735
1736 BundleException rethrow = null;
1737
1738 BundleInfo info = bundle.getInfo();
1739 if (info.getState() == Bundle.UNINSTALLED)
1740 {
1741 throw new IllegalStateException("The bundle is uninstalled.");
1742 }
1743
1744 // The spec says that uninstall should always succeed, so
1745 // catch an exception here if stop() doesn't succeed and
1746 // rethrow it at the end.
1747 try
1748 {
1749 stopBundle(bundle, true);
1750 }
1751 catch (BundleException ex)
1752 {
1753 rethrow = ex;
1754 }
1755
1756 // Remove the bundle from the installed map.
1757 BundleImpl target = null;
1758 synchronized (m_installedBundleLock_Priority2)
1759 {
1760 target = (BundleImpl) m_installedBundleMap.remove(info.getLocation());
1761 }
1762
1763 // Finally, put the uninstalled bundle into the
1764 // uninstalled list for subsequent refreshing.
1765 if (target != null)
1766 {
1767 // Set the bundle's persistent state to uninstalled.
1768 target.getInfo().setPersistentStateUninstalled();
1769
1770 // Mark bundle for removal.
1771 target.getInfo().setRemovalPending();
1772
1773 // Put bundle in uninstalled bundle array.
1774 rememberUninstalledBundle(bundle);
1775 }
1776 else
1777 {
1778 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001779 Logger.LOG_ERROR, "Unable to remove bundle from installed map!");
Richard S. Hall930fecc2005-08-16 18:33:34 +00001780 }
1781
1782 // Set state to uninstalled.
1783 info.setState(Bundle.UNINSTALLED);
Richard S. Hall69d84792006-01-13 13:55:13 +00001784 info.setLastModified(System.currentTimeMillis());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001785
1786 // Fire bundle event.
1787 fireBundleEvent(BundleEvent.UNINSTALLED, bundle);
1788
1789 if (rethrow != null)
1790 {
1791 throw rethrow;
1792 }
1793 }
1794
1795 //
1796 // Implementation of BundleContext interface methods.
1797 //
1798
1799 /**
1800 * Implementation for BundleContext.getProperty(). Returns
1801 * environment property associated with the framework.
1802 *
1803 * @param key The name of the property to retrieve.
1804 * @return The value of the specified property or null.
1805 **/
1806 protected String getProperty(String key)
1807 {
1808 // First, check the config properties.
Richard S. Hallea415752005-12-05 19:30:28 +00001809 String val = (String) m_config.get(key);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001810 // If not found, then try the system properties.
1811 return (val == null) ? System.getProperty(key) : val;
1812 }
1813
1814 protected Bundle installBundle(String location, InputStream is)
1815 throws BundleException
1816 {
1817 return installBundle(-1, location, is);
1818 }
1819
1820 private Bundle installBundle(long id, String location, InputStream is)
1821 throws BundleException
1822 {
1823 if (System.getSecurityManager() != null)
1824 {
1825 AccessController.checkPermission(m_adminPerm);
1826 }
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001827
Richard S. Hall930fecc2005-08-16 18:33:34 +00001828 BundleImpl bundle = null;
1829
1830 // Acquire an install lock.
1831 acquireInstallLock(location);
1832
1833 try
1834 {
1835 // Check to see if the framework is still running;
1836 if ((getStatus() == Felix.STOPPING_STATUS) ||
1837 (getStatus() == Felix.INITIAL_STATUS))
1838 {
1839 throw new BundleException("The framework has been shutdown.");
1840 }
1841
1842 // If bundle location is already installed, then
1843 // return it as required by the OSGi specification.
1844 bundle = (BundleImpl) getBundle(location);
1845 if (bundle != null)
1846 {
1847 return bundle;
1848 }
1849
1850 // Determine if this is a new or existing bundle.
1851 boolean isNew = (id < 0);
1852
1853 // If the bundle is new we must cache its JAR file.
1854 if (isNew)
1855 {
1856 // First generate an identifier for it.
1857 id = getNextId();
1858
1859 try
1860 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001861 // Add the bundle to the cache.
Richard S. Hall9a3e9852006-03-04 03:44:05 +00001862 m_cache.create(id, location, is);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001863 }
1864 catch (Exception ex)
1865 {
1866 throw new BundleException(
1867 "Unable to cache bundle: " + location, ex);
1868 }
1869 finally
1870 {
1871 try
1872 {
1873 if (is != null) is.close();
1874 }
1875 catch (IOException ex)
1876 {
1877 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001878 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001879 "Unable to close input stream.", ex);
1880 }
1881 }
1882 }
1883 else
1884 {
1885 // If the bundle we are installing is not new,
1886 // then try to purge old revisions before installing
1887 // it; this is done just in case a "refresh"
1888 // didn't occur last session...this would only be
1889 // due to an error or system crash.
1890 try
1891 {
1892 if (m_cache.getArchive(id).getRevisionCount() > 1)
1893 {
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001894 m_cache.getArchive(id).purge();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001895 }
1896 }
1897 catch (Exception ex)
1898 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001899 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001900 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001901 "Could not purge bundle.", ex);
1902 }
1903 }
1904
1905 try
1906 {
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001907 DefaultBundleArchive archive = m_cache.getArchive(id);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001908 bundle = new BundleImpl(this, createBundleInfo(archive));
1909 }
1910 catch (Exception ex)
1911 {
1912 // If the bundle is new, then remove it from the cache.
1913 // TODO: Perhaps it should be removed if it is not new too.
1914 if (isNew)
1915 {
1916 try
1917 {
1918 m_cache.remove(m_cache.getArchive(id));
1919 }
1920 catch (Exception ex1)
1921 {
1922 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001923 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001924 "Could not remove from cache.", ex1);
1925 }
1926 }
1927 throw new BundleException("Could not create bundle object.", ex);
1928 }
1929
1930 // If the bundle is new, then set its start level; existing
1931 // bundles already have their start level set.
1932 if (isNew)
1933 {
1934 // This will persistently set the bundle's start level.
1935 bundle.getInfo().setStartLevel(getInitialBundleStartLevel());
Richard S. Hall69d84792006-01-13 13:55:13 +00001936 bundle.getInfo().setLastModified(System.currentTimeMillis());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001937 }
1938
1939 synchronized (m_installedBundleLock_Priority2)
1940 {
1941 m_installedBundleMap.put(location, bundle);
1942 }
1943 }
1944 finally
1945 {
1946 // Always release install lock.
1947 releaseInstallLock(location);
1948
1949 // Always try to close the input stream.
1950 try
1951 {
1952 if (is != null) is.close();
1953 }
1954 catch (IOException ex)
1955 {
1956 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001957 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001958 "Unable to close input stream.", ex);
1959 // Not much else we can do.
1960 }
1961 }
1962
1963 // Fire bundle event.
1964 fireBundleEvent(BundleEvent.INSTALLED, bundle);
1965
1966 // Return new bundle.
1967 return bundle;
1968 }
1969
1970 /**
1971 * Retrieves a bundle from its location.
1972 *
1973 * @param location The location of the bundle to retrieve.
1974 * @return The bundle associated with the location or null if there
1975 * is no bundle associated with the location.
1976 **/
1977 protected Bundle getBundle(String location)
1978 {
1979 synchronized (m_installedBundleLock_Priority2)
1980 {
1981 return (Bundle) m_installedBundleMap.get(location);
1982 }
1983 }
1984
1985 /**
1986 * Implementation for BundleContext.getBundle(). Retrieves a
1987 * bundle from its identifier.
1988 *
1989 * @param id The identifier of the bundle to retrieve.
1990 * @return The bundle associated with the identifier or null if there
1991 * is no bundle associated with the identifier.
1992 **/
1993 protected Bundle getBundle(long id)
1994 {
1995 synchronized (m_installedBundleLock_Priority2)
1996 {
1997 BundleImpl bundle = null;
1998
1999 for (Iterator i = m_installedBundleMap.values().iterator(); i.hasNext(); )
2000 {
2001 bundle = (BundleImpl) i.next();
2002 if (bundle.getInfo().getBundleId() == id)
2003 {
2004 return bundle;
2005 }
2006 }
2007 }
2008
2009 return null;
2010 }
2011
2012 // Private member for method below.
2013 private Comparator m_comparator = null;
2014
2015 /**
2016 * Implementation for BundleContext.getBundles(). Retrieves
2017 * all installed bundles.
2018 *
2019 * @return An array containing all installed bundles or null if
2020 * there are no installed bundles.
2021 **/
2022 protected Bundle[] getBundles()
2023 {
2024 if (m_comparator == null)
2025 {
2026 m_comparator = new Comparator() {
2027 public int compare(Object o1, Object o2)
2028 {
2029 Bundle b1 = (Bundle) o1;
2030 Bundle b2 = (Bundle) o2;
2031 if (b1.getBundleId() > b2.getBundleId())
2032 return 1;
2033 else if (b1.getBundleId() < b2.getBundleId())
2034 return -1;
2035 return 0;
2036 }
2037 };
2038 }
2039
2040 Bundle[] bundles = null;
2041
2042 synchronized (m_installedBundleLock_Priority2)
2043 {
2044 if (m_installedBundleMap.size() == 0)
2045 {
2046 return null;
2047 }
2048
2049 bundles = new Bundle[m_installedBundleMap.size()];
2050 int counter = 0;
2051 for (Iterator i = m_installedBundleMap.values().iterator(); i.hasNext(); )
2052 {
2053 bundles[counter++] = (Bundle) i.next();
2054 }
2055 }
2056
2057 Arrays.sort(bundles, m_comparator);
2058
2059 return bundles;
2060 }
2061
2062 protected void addBundleListener(Bundle bundle, BundleListener l)
2063 {
2064 // The spec says do nothing if the listener is
2065 // already registered.
2066 BundleListenerWrapper old = (BundleListenerWrapper)
2067 m_dispatchQueue.getListener(BundleListener.class, l);
2068 if (old == null)
2069 {
2070 l = new BundleListenerWrapper(bundle, l);
2071 m_dispatchQueue.addListener(BundleListener.class, l);
2072 }
2073 }
2074
2075 protected void removeBundleListener(BundleListener l)
2076 {
2077 m_dispatchQueue.removeListener(BundleListener.class, l);
2078 }
2079
2080 /**
2081 * Implementation for BundleContext.addServiceListener().
2082 * Adds service listener to the listener list so that is
2083 * can listen for <code>ServiceEvent</code>s.
2084 *
2085 * @param bundle The bundle that registered the listener.
2086 * @param l The service listener to add to the listener list.
2087 * @param f The filter for the listener; may be null.
2088 **/
2089 protected void addServiceListener(Bundle bundle, ServiceListener l, String f)
2090 throws InvalidSyntaxException
2091 {
2092 // The spec says if the listener is already registered,
2093 // then replace filter.
2094 ServiceListenerWrapper old = (ServiceListenerWrapper)
2095 m_dispatchQueue.getListener(ServiceListener.class, l);
2096 if (old != null)
2097 {
2098 old.setFilter((f == null) ? null : new FilterImpl(m_logger, f));
2099 }
2100 else
2101 {
2102 l = new ServiceListenerWrapper(
2103 bundle, l, (f == null) ? null : new FilterImpl(m_logger, f));
2104 m_dispatchQueue.addListener(ServiceListener.class, l);
2105 }
2106 }
2107
2108 /**
2109 * Implementation for BundleContext.removeServiceListener().
2110 * Removes service listeners from the listener list.
2111 *
2112 * @param l The service listener to remove from the listener list.
2113 **/
2114 protected void removeServiceListener(ServiceListener l)
2115 {
2116 m_dispatchQueue.removeListener(ServiceListener.class, l);
2117 }
2118
2119 protected void addFrameworkListener(Bundle bundle, FrameworkListener l)
2120 {
2121 // The spec says do nothing if the listener is
2122 // already registered.
2123 FrameworkListenerWrapper old = (FrameworkListenerWrapper)
2124 m_dispatchQueue.getListener(FrameworkListener.class, l);
2125 if (old == null)
2126 {
2127 l = new FrameworkListenerWrapper(bundle, l);
2128 m_dispatchQueue.addListener(FrameworkListener.class, l);
2129 }
2130 }
2131
2132 protected void removeFrameworkListener(FrameworkListener l)
2133 {
2134 m_dispatchQueue.removeListener(FrameworkListener.class, l);
2135 }
2136
2137 /**
2138 * Remove all of the specified bundle's event listeners from
2139 * the framework.
2140 * @param bundle The bundle whose listeners are to be removed.
2141 **/
2142 private void removeListeners(Bundle bundle)
2143 {
2144 if (bundle == null)
2145 {
2146 return;
2147 }
2148
2149 // Remove all listeners associated with the supplied bundle;
2150 // it is only possible to know the bundle associated with a
2151 // listener if the listener was wrapper by a ListenerWrapper,
2152 // so look for those.
2153 Object[] listeners = m_dispatchQueue.getListeners();
2154 for (int i = listeners.length - 2; i >= 0; i -= 2)
2155 {
2156 // Check for listener wrappers and then compare the bundle.
2157 if (listeners[i + 1] instanceof ListenerWrapper)
2158 {
2159 ListenerWrapper lw = (ListenerWrapper) listeners[i + 1];
2160 if ((lw.getBundle() != null) && (lw.getBundle().equals(bundle)))
2161 {
2162 m_dispatchQueue.removeListener(
2163 (Class) listeners[i], (EventListener) listeners[i+1]);
2164 }
2165 }
2166 }
2167 }
2168
2169 /**
2170 * Implementation for BundleContext.registerService(). Registers
2171 * a service for the specified bundle bundle.
2172 *
2173 * @param classNames A string array containing the names of the classes
2174 * under which the new service is available.
2175 * @param svcObj The service object or <code>ServiceFactory</code>.
2176 * @param dict A dictionary of properties that further describe the
2177 * service or null.
2178 * @return A <code>ServiceRegistration</code> object or null.
2179 **/
2180 protected ServiceRegistration registerService(
2181 BundleImpl bundle, String[] classNames, Object svcObj, Dictionary dict)
2182 {
2183 if (classNames == null)
2184 {
2185 throw new NullPointerException("Service class names cannot be null.");
2186 }
2187 else if (svcObj == null)
2188 {
2189 throw new IllegalArgumentException("Service object cannot be null.");
2190 }
2191
2192 // Check for permission to register all passed in interface names.
2193 if (System.getSecurityManager() != null)
2194 {
2195 for (int i = 0; i < classNames.length; i++)
2196 {
2197 ServicePermission perm = new ServicePermission(
2198 classNames[i], ServicePermission.REGISTER);
2199 AccessController.checkPermission(perm);
2200 }
2201 }
2202
2203 // Acquire bundle lock.
Richard S. Hall3c26cc02006-02-17 13:51:21 +00002204 acquireBundleLock(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002205
2206 ServiceRegistration reg = null;
2207
2208 try
2209 {
2210 BundleInfo info = bundle.getInfo();
2211
2212 // Can only register services if starting or active.
2213 if ((info.getState() & (Bundle.STARTING | Bundle.ACTIVE)) == 0)
2214 {
2215 throw new IllegalStateException(
2216 "Can only register services while bundle is active or activating.");
2217 }
2218
2219 // Check to make sure that the service object is
2220 // an instance of all service classes; ignore if
2221 // service object is a service factory.
2222 if (!(svcObj instanceof ServiceFactory))
2223 {
2224 for (int i = 0; i < classNames.length; i++)
2225 {
2226 Class clazz = loadClassUsingClass(svcObj.getClass(), classNames[i]);
2227 if (clazz == null)
2228 {
2229 throw new IllegalArgumentException(
2230 "Cannot cast service: " + classNames[i]);
2231 }
2232 else if (!clazz.isAssignableFrom(svcObj.getClass()))
2233 {
2234 throw new IllegalArgumentException(
2235 "Service object is not an instance of \""
2236 + classNames[i] + "\".");
2237 }
2238 }
2239 }
2240
2241 reg = m_registry.registerService(bundle, classNames, svcObj, dict);
2242 }
2243 finally
2244 {
2245 // Always release bundle lock.
2246 releaseBundleLock(bundle);
2247 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +00002248
2249 // TODO: CONCURRENCY - Reconsider firing event here, outside of the
2250 // bundle lock.
2251
Richard S. Hall930fecc2005-08-16 18:33:34 +00002252 // NOTE: The service registered event is fired from the service
2253 // registry to the framework, where it is then redistributed to
2254 // interested service event listeners.
2255
2256 return reg;
2257 }
2258
2259 /**
2260 * <p>
2261 * This is a simple utility class that attempts to load the named
2262 * class using the class loader of the supplied class or
2263 * the class loader of one of its super classes or their implemented
2264 * interfaces. This is necessary during service registration to test
2265 * whether a given service object implements its declared service
2266 * interfaces.
2267 * </p>
2268 * <p>
2269 * To perform this test, the framework must try to load
2270 * the classes associated with the declared service interfaces, so
2271 * it must choose a class loader. The class loader of the registering
2272 * bundle cannot be used, since this disallows third parties to
2273 * register service on behalf of another bundle. Consequently, the
2274 * class loader of the service object must be used. However, this is
2275 * also not sufficient since the class loader of the service object
2276 * may not have direct access to the class in question.
2277 * </p>
2278 * <p>
2279 * The service object's class loader may not have direct access to
2280 * its service interface if it extends a super class from another
2281 * bundle which implements the service interface from an imported
2282 * bundle or if it implements an extension of the service interface
2283 * from another bundle which imports the base interface from another
2284 * bundle. In these cases, the service object's class loader only has
2285 * access to the super class's class or the extended service interface,
2286 * respectively, but not to the actual service interface.
2287 * </p>
2288 * <p>
2289 * Thus, it is necessary to not only try to load the service interface
2290 * class from the service object's class loader, but from the class
2291 * loaders of any interfaces it implements and the class loaders of
2292 * all super classes.
2293 * </p>
2294 * @param svcObj the class that is the root of the search.
2295 * @param name the name of the class to load.
2296 * @return the loaded class or <tt>null</tt> if it could not be
2297 * loaded.
2298 **/
2299 private static Class loadClassUsingClass(Class clazz, String name)
2300 {
2301 while (clazz != null)
2302 {
2303 // Get the class loader of the current class object.
2304 ClassLoader loader = clazz.getClassLoader();
2305 // A null class loader represents the system class loader.
2306 loader = (loader == null) ? ClassLoader.getSystemClassLoader() : loader;
2307 try
2308 {
2309 return loader.loadClass(name);
2310 }
2311 catch (ClassNotFoundException ex)
2312 {
2313 // Ignore and try interface class loaders.
2314 }
2315
2316 // Try to see if we can load the class from
2317 // one of the class's implemented interface
2318 // class loaders.
2319 Class[] ifcs = clazz.getInterfaces();
2320 for (int i = 0; i < ifcs.length; i++)
2321 {
2322 clazz = loadClassUsingClass(ifcs[i], name);
2323 if (clazz != null)
2324 {
2325 return clazz;
2326 }
2327 }
2328
2329 // Try to see if we can load the class from
2330 // the super class class loader.
2331 clazz = clazz.getSuperclass();
2332 }
2333
2334 return null;
2335 }
2336
2337 protected ServiceReference[] getServiceReferences(
2338 BundleImpl bundle, String className, String expr)
2339 throws InvalidSyntaxException
2340 {
2341 // Define filter if expression is not null.
2342 Filter filter = null;
2343 if (expr != null)
2344 {
2345 filter = new FilterImpl(m_logger, expr);
2346 }
2347
2348 // Ask the service registry for all matching service references.
2349 List refList = m_registry.getServiceReferences(className, filter);
2350
2351 // The returned reference list must be filtered for two cases:
2352 // 1) The requesting bundle may not be wired to the same class
2353 // as the providing bundle (i.e, different versions), so filter
2354 // any services for which the requesting bundle might get a
2355 // class cast exception.
2356 // 2) Security is enabled and the requesting bundle does not have
2357 // permission access the service.
2358 for (int refIdx = 0; (refList != null) && (refIdx < refList.size()); refIdx++)
2359 {
2360 // Get the current service reference.
2361 ServiceReference ref = (ServiceReference) refList.get(refIdx);
2362
2363 // Get the service's objectClass property.
2364 String[] objectClass = (String[]) ref.getProperty(FelixConstants.OBJECTCLASS);
2365
2366 // Boolean flag.
2367 boolean allow = false;
2368
2369 // Filter the service reference if the requesting bundle
2370 // does not have permission.
2371 if (System.getSecurityManager() != null)
2372 {
2373 for (int classIdx = 0;
2374 !allow && (classIdx < objectClass.length);
2375 classIdx++)
2376 {
2377 try
2378 {
2379 ServicePermission perm = new ServicePermission(
2380 objectClass[classIdx], ServicePermission.GET);
2381 AccessController.checkPermission(perm);
2382 // The bundle only needs permission for one
2383 // of the service interfaces, so break out
2384 // of the loop when permission is granted.
2385 allow = true;
2386 }
2387 catch (Exception ex)
2388 {
2389 // We do not throw this exception since the bundle
2390 // is not supposed to know about the service at all
2391 // if it does not have permission.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002392 m_logger.log(Logger.LOG_ERROR, ex.getMessage());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002393 }
2394 }
2395
2396 if (!allow)
2397 {
2398 refList.remove(refIdx);
2399 refIdx--;
2400 continue;
2401 }
2402 }
2403
2404 // Now check for castability.
2405 if (!isServiceAssignable(bundle, ref))
2406 {
2407 refList.remove(refIdx);
2408 refIdx--;
2409 }
2410 }
2411
2412 if (refList.size() > 0)
2413 {
2414 return (ServiceReference[]) refList.toArray(new ServiceReference[refList.size()]);
2415 }
2416
2417 return null;
2418 }
2419
2420 /**
2421 * This method determines if the requesting bundle is able to cast
2422 * the specified service reference based on class visibility rules
2423 * of the underlying modules.
2424 * @param requester The bundle requesting the service.
2425 * @param ref The service in question.
2426 * @return <tt>true</tt> if the requesting bundle is able to case
2427 * the service object to a known type.
2428 **/
2429 protected boolean isServiceAssignable(BundleImpl requester, ServiceReference ref)
2430 {
2431 // Boolean flag.
2432 boolean allow = true;
2433 // Get the service's objectClass property.
2434 String[] objectClass = (String[]) ref.getProperty(FelixConstants.OBJECTCLASS);
2435
2436 // The the service reference is not assignable when the requesting
2437 // bundle is wired to a different version of the service object.
2438 // NOTE: We are pessimistic here, if any class in the service's
2439 // objectClass is not usable by the requesting bundle, then we
2440 // disallow the service reference.
2441 for (int classIdx = 0; (allow) && (classIdx < objectClass.length); classIdx++)
2442 {
2443 if (!ref.isAssignableTo(requester, objectClass[classIdx]))
2444 {
2445 allow = false;
2446 }
2447 }
2448 return allow;
2449 }
2450
2451 protected Object getService(Bundle bundle, ServiceReference ref)
2452 {
2453 // Check that the bundle has permission to get at least
2454 // one of the service interfaces; the objectClass property
2455 // of the service stores its service interfaces.
2456 String[] objectClass = (String[])
2457 ref.getProperty(Constants.OBJECTCLASS);
2458 if (objectClass == null)
2459 {
2460 return null;
2461 }
2462
2463 boolean hasPermission = false;
2464 if (System.getSecurityManager() != null)
2465 {
2466 for (int i = 0;
2467 !hasPermission && (i < objectClass.length);
2468 i++)
2469 {
2470 try
2471 {
2472 ServicePermission perm =
2473 new ServicePermission(
2474 objectClass[i], ServicePermission.GET);
2475 AccessController.checkPermission(perm);
2476 hasPermission = true;
2477 }
2478 catch (Exception ex)
2479 {
2480 }
2481 }
2482 }
2483 else
2484 {
2485 hasPermission = true;
2486 }
2487
2488 // If the bundle does not permission to access the service,
2489 // then return null.
2490 if (!hasPermission)
2491 {
2492 return null;
2493 }
2494
2495 return m_registry.getService(bundle, ref);
2496 }
2497
2498 protected boolean ungetService(Bundle bundle, ServiceReference ref)
2499 {
2500 return m_registry.ungetService(bundle, ref);
2501 }
2502
2503 protected File getDataFile(BundleImpl bundle, String s)
2504 {
2505 // The spec says to throw an error if the bundle
2506 // is stopped, which I assume means not active,
2507 // starting, or stopping.
2508 if ((bundle.getInfo().getState() != Bundle.ACTIVE) &&
2509 (bundle.getInfo().getState() != Bundle.STARTING) &&
2510 (bundle.getInfo().getState() != Bundle.STOPPING))
2511 {
2512 throw new IllegalStateException("Only active bundles can create files.");
2513 }
2514 try
2515 {
2516 return m_cache.getArchive(
2517 bundle.getInfo().getBundleId()).getDataFile(s);
2518 }
2519 catch (Exception ex)
2520 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002521 m_logger.log(Logger.LOG_ERROR, ex.getMessage());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002522 return null;
2523 }
2524 }
2525
2526 //
2527 // PackageAdmin related methods.
2528 //
2529
2530 /**
2531 * Returns the exported package associated with the specified
2532 * package name. This is used by the PackageAdmin service
2533 * implementation.
2534 *
2535 * @param name The name of the exported package to find.
2536 * @return The exported package or null if no matching package was found.
2537 **/
Richard S. Hallafc52d42006-02-09 13:04:32 +00002538 protected ExportedPackage getExportedPackage(String name)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002539 {
Richard S. Hallafc52d42006-02-09 13:04:32 +00002540 ExportedPackage[] pkgs = getExportedPackages(name);
2541 // There can be multiple versions of the same package exported,
2542 // so we will just return the first one.
2543 return (pkgs != null) ? pkgs[0] : null;
2544 }
2545
2546 /**
2547 * Returns the exported package associated with the specified
2548 * package name. This is used by the PackageAdmin service
2549 * implementation.
2550 *
2551 * @param name The name of the exported package to find.
2552 * @return The exported package or null if no matching package was found.
2553 **/
2554 protected ExportedPackage[] getExportedPackages(String name)
2555 {
2556 // First, get all exporters of the package.
2557 ExportedPackage[] pkgs = null;
2558 IModule[] exporters = m_policyCore.getInUseExporters(new R4Import(name, null, null));
Richard S. Hall930fecc2005-08-16 18:33:34 +00002559 if (exporters != null)
2560 {
Richard S. Hall88e0ae62006-02-09 13:22:21 +00002561 pkgs = new ExportedPackage[exporters.length];
Richard S. Hallafc52d42006-02-09 13:04:32 +00002562 for (int pkgIdx = 0; pkgIdx < pkgs.length; pkgIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002563 {
Richard S. Hallafc52d42006-02-09 13:04:32 +00002564 // Get the bundle associated with the current exporting module.
2565 BundleImpl bundle = (BundleImpl) getBundle(
2566 Util.getBundleIdFromModuleId(exporters[pkgIdx].getId()));
2567
2568 // We need to find the version of the exported package, but this
2569 // is tricky since there may be multiple versions of the package
2570 // offered by a given bundle, since multiple revisions of the
2571 // bundle JAR file may exist if the bundle was updated without
2572 // refreshing the framework. In this case, each revision of the
2573 // bundle JAR file is represented as a module in the BundleInfo
2574 // module array, which is ordered from oldest to newest. We assume
2575 // that the first module found to be exporting the package is the
2576 // provider of the package, which makes sense since it must have
2577 // been resolved first.
2578 IModule[] modules = bundle.getInfo().getModules();
2579 for (int modIdx = 0; modIdx < modules.length; modIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002580 {
Richard S. Hallafc52d42006-02-09 13:04:32 +00002581 R4Export export = Util.getExportPackage(modules[modIdx], name);
2582 if (export != null)
2583 {
2584 pkgs[pkgIdx] =
2585 new ExportedPackageImpl(
2586 this, bundle, name, export.getVersion());
2587 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002588 }
2589 }
2590 }
2591
Richard S. Hallafc52d42006-02-09 13:04:32 +00002592 return pkgs;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002593 }
2594
2595 /**
2596 * Returns an array of all actively exported packages from the specified
2597 * bundle or if the specified bundle is <tt>null</tt> an array
2598 * containing all actively exported packages by all bundles.
2599 *
2600 * @param b The bundle whose exported packages are to be retrieved
2601 * or <tt>null</tt> if the exported packages of all bundles are
2602 * to be retrieved.
2603 * @return An array of exported packages.
2604 **/
2605 protected ExportedPackage[] getExportedPackages(Bundle b)
2606 {
2607 List list = new ArrayList();
2608
2609 // If a bundle is specified, then return its
2610 // exported packages.
2611 if (b != null)
2612 {
2613 BundleImpl bundle = (BundleImpl) b;
2614 getExportedPackages(bundle, list);
2615 }
2616 // Otherwise return all exported packages.
2617 else
2618 {
2619 // To create a list of all exported packages, we must look
2620 // in the installed and uninstalled sets of bundles. To
2621 // ensure a somewhat consistent view, we will gather all
2622 // of this information from within the installed bundle
2623 // lock.
2624 synchronized (m_installedBundleLock_Priority2)
2625 {
2626 // First get exported packages from uninstalled bundles.
2627 synchronized (m_uninstalledBundlesLock_Priority3)
2628 {
2629 for (int bundleIdx = 0;
2630 (m_uninstalledBundles != null) && (bundleIdx < m_uninstalledBundles.length);
2631 bundleIdx++)
2632 {
2633 BundleImpl bundle = m_uninstalledBundles[bundleIdx];
2634 getExportedPackages(bundle, list);
2635 }
2636 }
2637
2638 // Now get exported packages from installed bundles.
2639 Bundle[] bundles = getBundles();
2640 for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
2641 {
2642 BundleImpl bundle = (BundleImpl) bundles[bundleIdx];
2643 getExportedPackages(bundle, list);
2644 }
2645 }
2646 }
2647
2648 return (ExportedPackage[]) list.toArray(new ExportedPackage[list.size()]);
2649 }
2650
2651 /**
2652 * Adds any current active exported packages from the specified bundle
2653 * to the passed in list.
2654 * @param bundle The bundle from which to retrieve exported packages.
2655 * @param list The list to which the exported packages are added
2656 **/
2657 private void getExportedPackages(BundleImpl bundle, List list)
2658 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002659 // Since a bundle may have many modules associated with it,
2660 // one for each revision in the cache, search each module
2661 // for each revision to get all exports.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002662 IModule[] modules = bundle.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002663 for (int modIdx = 0; modIdx < modules.length; modIdx++)
2664 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002665 R4Export[] exports = m_policyCore.getExports(modules[modIdx]);
2666 if ((exports != null) && (exports.length > 0))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002667 {
2668 for (int expIdx = 0; expIdx < exports.length; expIdx++)
2669 {
2670 // See if the target bundle's module is one of the
2671 // "in use" exporters of the package.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002672 IModule[] inUseModules =
2673 m_policyCore.getInUseExporters(
2674 new R4Import(exports[expIdx].getName(), null, null));
2675 // Search through the current providers to find the target
2676 // module.
2677 for (int i = 0; (inUseModules != null) && (i < inUseModules.length); i++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002678 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002679 if (inUseModules[i] == modules[modIdx])
2680 {
2681 list.add(new ExportedPackageImpl(
2682 this, bundle, exports[expIdx].getName(),
2683 exports[expIdx].getVersion()));
2684 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002685 }
2686 }
2687 }
2688 }
2689 }
2690
2691 protected Bundle[] getImportingBundles(ExportedPackage ep)
2692 {
2693 // Get exporting bundle; we need to use this internal
2694 // method because the spec says ep.getExportingBundle()
2695 // should return null if the package is stale.
2696 BundleImpl exporter = (BundleImpl)
2697 ((ExportedPackageImpl) ep).getExportingBundleInternal();
2698 BundleInfo exporterInfo = exporter.getInfo();
2699
2700 // Create list for storing importing bundles.
2701 List list = new ArrayList();
2702 Bundle[] bundles = getBundles();
2703
2704 // Check all bundles to see who imports the package.
2705 for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
2706 {
2707 BundleImpl importer = (BundleImpl) bundles[bundleIdx];
2708
2709 // Ignore the bundle if it imports from itself.
2710 if (exporter != importer)
2711 {
2712 // Check the import wires of all modules for all bundles.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002713 IModule[] modules = importer.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002714 for (int modIdx = 0; modIdx < modules.length; modIdx++)
2715 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002716 R4Wire wire = Util.getWire(modules[modIdx], ep.getName());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002717
2718 // If the resolving module is associated with the
2719 // exporting bundle, then add current bundle to
2720 // import list.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002721 if ((wire != null) && exporterInfo.hasModule(wire.getExportingModule()))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002722 {
2723 // Add the bundle to the list of importers.
2724 list.add(bundles[bundleIdx]);
2725 break;
2726 }
2727 }
2728 }
2729 }
2730
2731 // Return the results.
2732 if (list.size() > 0)
2733 {
2734 return (Bundle[]) list.toArray(new Bundle[list.size()]);
2735 }
2736
2737 return null;
2738 }
2739
2740 protected void refreshPackages(Bundle[] targets)
2741 {
2742 if (System.getSecurityManager() != null)
2743 {
2744 AccessController.checkPermission(m_adminPerm);
2745 }
2746
2747 // Acquire locks for all impacted bundles.
2748 BundleImpl[] bundles = acquireBundleRefreshLocks(targets);
2749
2750 // Remove any targeted bundles from the uninstalled bundles
2751 // array, since they will be removed from the system after
2752 // the refresh.
2753 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
2754 {
2755 forgetUninstalledBundle(bundles[i]);
2756 }
2757
2758 try
2759 {
2760 // If there are targets, then refresh each one.
2761 if (bundles != null)
2762 {
2763 // At this point the map contains every bundle that has been
2764 // updated and/or removed as well as all bundles that import
2765 // packages from these bundles.
2766
2767 // Create refresh helpers for each bundle.
2768 RefreshHelper[] helpers = new RefreshHelper[bundles.length];
2769 for (int i = 0; i < bundles.length; i++)
2770 {
2771 helpers[i] = new RefreshHelper(bundles[i]);
2772 }
2773
2774 // Stop, purge or remove, and reinitialize all bundles first.
2775 for (int i = 0; i < helpers.length; i++)
2776 {
2777 helpers[i].stop();
2778 helpers[i].purgeOrRemove();
2779 helpers[i].reinitialize();
2780 }
2781
2782 // Then restart all bundles that were previously running.
2783 for (int i = 0; i < helpers.length; i++)
2784 {
2785 helpers[i].restart();
2786 }
2787 }
2788 }
2789 finally
2790 {
2791 // Always release all bundle locks.
2792 releaseBundleLocks(bundles);
2793 }
2794
2795 fireFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, getBundle(0), null);
2796 }
2797
2798 private void populateImportGraph(BundleImpl target, Map map)
2799 {
2800 // Get the exported packages for the specified bundle.
2801 ExportedPackage[] pkgs = getExportedPackages(target);
2802
2803 for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
2804 {
2805 // Get all imports of this package.
2806 Bundle[] importers = getImportingBundles(pkgs[pkgIdx]);
2807
2808 for (int impIdx = 0;
2809 (importers != null) && (impIdx < importers.length);
2810 impIdx++)
2811 {
Richard S. Halle34df092005-10-06 17:03:05 +00002812 // Avoid cycles if the bundle is already in map.
2813 if (!map.containsKey(importers[impIdx]))
2814 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002815 // Add each importing bundle to map.
2816 map.put(importers[impIdx], importers[impIdx]);
2817 // Now recurse into each bundle to get its importers.
2818 populateImportGraph(
2819 (BundleImpl) importers[impIdx], map);
Richard S. Halle34df092005-10-06 17:03:05 +00002820 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002821 }
2822 }
2823 }
2824
2825 //
2826 // Miscellaneous private methods.
2827 //
2828
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00002829 private BundleInfo createBundleInfo(DefaultBundleArchive archive)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002830 throws Exception
2831 {
2832 // Get the bundle manifest.
2833 Map headerMap = null;
2834 try
2835 {
2836 // Although there should only ever be one revision at this
2837 // point, get the header for the current revision to be safe.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00002838 headerMap = archive.getRevision(archive.getRevisionCount() - 1).getManifestHeader();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002839 }
2840 catch (Exception ex)
2841 {
2842 throw new BundleException("Unable to read JAR manifest.", ex);
2843 }
2844
2845 // We can't do anything without the manifest header.
2846 if (headerMap == null)
2847 {
2848 throw new BundleException("Unable to read JAR manifest header.");
2849 }
2850
2851 // Create the module for the bundle; although there should only
2852 // ever be one revision at this point, create the module for
2853 // the current revision to be safe.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002854 IModule module = createModule(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002855 archive.getId(), archive.getRevisionCount() - 1, headerMap);
2856
2857 // Finally, create an return the bundle info.
2858 return new BundleInfo(m_logger, archive, module);
2859 }
2860
2861 /**
2862 * Creates a module for a given bundle by reading the bundle's
2863 * manifest meta-data and converting it to work with the underlying
2864 * import/export search policy of the module loader.
2865 * @param id The identifier of the bundle for which the module should
2866 * be created.
2867 * @param headers The headers map associated with the bundle.
2868 * @return The initialized and/or newly created module.
2869 **/
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002870 private IModule createModule(long id, int revision, Map headerMap)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002871 throws Exception
2872 {
2873 // Get the manifest version.
2874 String version = (String) headerMap.get(FelixConstants.BUNDLE_MANIFESTVERSION);
2875 version = (version == null) ? "1" : version;
2876 if (!version.equals("1") && !version.equals("2"))
2877 {
2878 throw new BundleException("Unknown 'Bundle-ManifestVersion' value: " + version);
2879 }
2880
Richard S. Hallb72001a2006-02-20 15:10:33 +00002881 // Create map to check for duplicate imports/exports.
2882 Map dupeMap = new HashMap();
2883
Richard S. Hall930fecc2005-08-16 18:33:34 +00002884 // Get import packages from bundle manifest.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002885 R4Package[] pkgs = R4Package.parseImportOrExportHeader(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002886 (String) headerMap.get(Constants.IMPORT_PACKAGE));
Richard S. Hallb72001a2006-02-20 15:10:33 +00002887
2888 // Create non-duplicated import array.
2889 dupeMap.clear();
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002890 for (int i = 0; i < pkgs.length; i++)
2891 {
Richard S. Hallb72001a2006-02-20 15:10:33 +00002892 if (dupeMap.get(pkgs[i].getName()) == null)
2893 {
2894 dupeMap.put(pkgs[i].getName(), new R4Import(pkgs[i]));
2895 }
2896 else
2897 {
2898 // TODO: FRAMEWORK - Determine if we should error here.
2899 m_logger.log(Logger.LOG_WARNING,
2900 "Duplicate import - " + pkgs[i].getName());
2901 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002902 }
Richard S. Hallb72001a2006-02-20 15:10:33 +00002903 R4Import[] imports =
2904 (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.size()]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002905
2906 // Check to make sure that R3 bundles have only specified
2907 // the 'specification-version' attribute and no directives.
2908 if (version.equals("1"))
2909 {
2910 for (int i = 0; (imports != null) && (i < imports.length); i++)
2911 {
2912 if (imports[i].getDirectives().length != 0)
2913 {
2914 throw new BundleException("R3 imports cannot contain directives.");
2915 }
2916 // NOTE: This is checking for "version" rather than "specification-version"
2917 // because the package class normalizes to "version" to avoid having
2918 // future special cases. This could be changed if more strict behavior
2919 // is required.
2920 if ((imports[i].getVersionHigh() != null) ||
2921 (imports[i].getAttributes().length > 1) ||
2922 ((imports[i].getAttributes().length == 1) &&
2923 (!imports[i].getAttributes()[0].getName().equals(FelixConstants.VERSION_ATTRIBUTE))))
2924 {
2925 throw new BundleException(
2926 "Import does not conform to R3 syntax: " + imports[i]);
2927 }
2928 }
2929 }
2930
2931 // Get export packages from bundle manifest.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002932 pkgs = R4Package.parseImportOrExportHeader(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002933 (String) headerMap.get(Constants.EXPORT_PACKAGE));
Richard S. Hallb72001a2006-02-20 15:10:33 +00002934
2935 // Create non-duplicated export array.
2936 dupeMap.clear();
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002937 for (int i = 0; i < pkgs.length; i++)
2938 {
Richard S. Hallb72001a2006-02-20 15:10:33 +00002939 if (dupeMap.get(pkgs[i].getName()) == null)
2940 {
2941 dupeMap.put(pkgs[i].getName(), new R4Export(pkgs[i]));
2942 }
2943 else
2944 {
2945 // TODO: FRAMEWORK - Exports can be duplicated, so fix this.
2946 m_logger.log(Logger.LOG_WARNING,
2947 "Duplicate export - " + pkgs[i].getName());
2948 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002949 }
Richard S. Hallb72001a2006-02-20 15:10:33 +00002950 R4Export[] exports =
2951 (R4Export[]) dupeMap.values().toArray(new R4Export[dupeMap.size()]);
2952
Richard S. Hall930fecc2005-08-16 18:33:34 +00002953
2954 // Check to make sure that R3 bundles have only specified
2955 // the 'specification-version' attribute and no directives.
2956 // In addition, all R3 exports imply imports, so add a
2957 // corresponding import for each export.
2958 if (version.equals("1"))
2959 {
2960 for (int i = 0; (exports != null) && (i < exports.length); i++)
2961 {
2962 if (exports[i].getDirectives().length != 0)
2963 {
2964 throw new BundleException("R3 exports cannot contain directives.");
2965 }
2966 // NOTE: This is checking for "version" rather than "specification-version"
2967 // because the package class normalizes to "version" to avoid having
2968 // future special cases. This could be changed if more strict behavior
2969 // is required.
2970 if ((exports[i].getAttributes().length > 1) ||
2971 ((exports[i].getAttributes().length == 1) &&
2972 (!exports[i].getAttributes()[0].getName().equals(FelixConstants.VERSION_ATTRIBUTE))))
2973 {
2974 throw new BundleException(
2975 "Export does not conform to R3 syntax: " + imports[i]);
2976 }
2977 }
2978
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002979 R4Import[] newImports = new R4Import[imports.length + exports.length];
Richard S. Hall930fecc2005-08-16 18:33:34 +00002980 System.arraycopy(imports, 0, newImports, 0, imports.length);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002981 for (int i = 0; i < exports.length; i++)
2982 {
2983 newImports[i + imports.length] = new R4Import(exports[i]);
2984 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002985 imports = newImports;
2986 }
2987
2988 // For R3 bundles, add a "uses" directive onto each export
2989 // that references every other import (which will include
2990 // exports, since export implies import); this is
2991 // necessary since R3 bundles assumed a single class space,
2992 // but R4 allows for multiple class spaces.
2993 if (version.equals("1"))
2994 {
2995 String usesValue = "";
2996 for (int i = 0; (imports != null) && (i < imports.length); i++)
2997 {
2998 usesValue = usesValue
2999 + ((usesValue.length() > 0) ? "," : "")
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003000 + imports[i].getName();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003001 }
3002 R4Directive uses = new R4Directive(
3003 FelixConstants.USES_DIRECTIVE, usesValue);
3004 for (int i = 0; (exports != null) && (i < exports.length); i++)
3005 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003006 exports[i] = new R4Export(
3007 exports[i].getName(),
Richard S. Hall930fecc2005-08-16 18:33:34 +00003008 new R4Directive[] { uses },
3009 exports[i].getAttributes());
3010 }
3011 }
3012
Richard S. Hall930fecc2005-08-16 18:33:34 +00003013 // Get dynamic import packages from bundle manifest.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003014 pkgs = R4Package.parseImportOrExportHeader(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003015 (String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
Richard S. Hallb72001a2006-02-20 15:10:33 +00003016
3017 // Create non-duplicated dynamic import array.
3018 dupeMap.clear();
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003019 for (int i = 0; i < pkgs.length; i++)
3020 {
Richard S. Hallb72001a2006-02-20 15:10:33 +00003021 if (dupeMap.get(pkgs[i].getName()) == null)
3022 {
3023 dupeMap.put(pkgs[i].getName(), new R4Import(pkgs[i]));
3024 }
3025 else
3026 {
3027 // TODO: FRAMEWORK - Determine if we should error here.
3028 m_logger.log(Logger.LOG_WARNING,
3029 "Duplicate import - " + pkgs[i].getName());
3030 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003031 }
Richard S. Hallb72001a2006-02-20 15:10:33 +00003032 R4Import[] dynamics =
3033 (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.size()]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003034
3035 // Check to make sure that R3 bundles have no attributes or
3036 // directives.
3037 if (version.equals("1"))
3038 {
3039 for (int i = 0; (dynamics != null) && (i < dynamics.length); i++)
3040 {
3041 if (dynamics[i].getDirectives().length != 0)
3042 {
3043 throw new BundleException("R3 dynamic imports cannot contain directives.");
3044 }
3045 if (dynamics[i].getAttributes().length != 0)
3046 {
3047 throw new BundleException("R3 dynamic imports cannot contain attributes.");
3048 }
3049 }
3050 }
3051
Richard S. Hall930fecc2005-08-16 18:33:34 +00003052 // Get native library entry names for module library sources.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003053 R4LibraryHeader[] libraryHeaders =
Richard S. Hall930fecc2005-08-16 18:33:34 +00003054 Util.parseLibraryStrings(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003055 m_logger,
Richard S. Hall930fecc2005-08-16 18:33:34 +00003056 Util.parseDelimitedString(
3057 (String) headerMap.get(Constants.BUNDLE_NATIVECODE), ","));
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003058 R4Library[] libraries = new R4Library[libraryHeaders.length];
3059 for (int i = 0; i < libraries.length; i++)
3060 {
3061 libraries[i] = new R4Library(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003062 m_logger, m_cache, id, revision,
3063 getProperty(Constants.FRAMEWORK_OS_NAME),
3064 getProperty(Constants.FRAMEWORK_PROCESSOR),
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003065 libraryHeaders[i]);
3066 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003067
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003068 // Now that we have all of the metadata associated with the
3069 // module, we need to create the module itself. This is somewhat
3070 // complicated because a module is constructed out of several
3071 // interrelated pieces (e.g., content loader, search policy,
3072 // url policy). We need to create all of these pieces and bind
3073 // them together.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003074
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003075 // First, create the module.
3076 IModule module = m_factory.createModule(
3077 Long.toString(id) + "." + Integer.toString(revision));
3078 // Attach the R4 search policy metadata to the module.
3079 m_policyCore.setExports(module, exports);
3080 m_policyCore.setImports(module, imports);
3081 m_policyCore.setDynamicImports(module, dynamics);
3082 m_policyCore.setLibraries(module, libraries);
3083
3084 // Create the content loader associated with the module archive.
3085 IContentLoader contentLoader = new ContentLoaderImpl(
3086 m_logger,
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00003087 m_cache.getArchive(id).getRevision(revision).getContent(),
3088 m_cache.getArchive(id).getRevision(revision).getContentPath());
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003089 // Set the content loader's search policy.
3090 contentLoader.setSearchPolicy(
3091 new R4SearchPolicy(m_policyCore, module));
3092 // Set the content loader's URL policy.
3093 contentLoader.setURLPolicy(
Richard S. Hallfb5221e2006-02-20 10:22:28 +00003094// TODO: ML - SUCKS NEEDING URL POLICY PER MODULE.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003095 new URLPolicyImpl(
3096 m_logger, m_bundleStreamHandler, module));
3097
3098 // Set the module's content loader to the created content loader.
3099 m_factory.setContentLoader(module, contentLoader);
3100
3101 // Done, so return the module.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003102 return module;
3103 }
3104
3105 private BundleActivator createBundleActivator(BundleInfo info)
3106 throws Exception
3107 {
3108 // CONCURRENCY NOTE:
3109 // This method is called indirectly from startBundle() (via _startBundle()),
3110 // which has the exclusion lock, so there is no need to do any locking here.
3111
3112 BundleActivator activator = null;
3113
3114 String strict = m_config.get(FelixConstants.STRICT_OSGI_PROP);
3115 boolean isStrict = (strict == null) ? true : strict.equals("true");
3116 if (!isStrict)
3117 {
3118 try
3119 {
3120 activator =
3121 m_cache.getArchive(info.getBundleId())
Richard S. Hallf1359482006-02-14 08:02:51 +00003122 .getActivator(info.getCurrentModule());
Richard S. Hall930fecc2005-08-16 18:33:34 +00003123 }
3124 catch (Exception ex)
3125 {
3126 activator = null;
3127 }
3128 }
3129
3130 // If there was no cached activator, then get the activator
3131 // class from the bundle manifest.
3132 if (activator == null)
3133 {
3134 // Get the associated bundle archive.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00003135 DefaultBundleArchive ba = m_cache.getArchive(info.getBundleId());
Richard S. Hall930fecc2005-08-16 18:33:34 +00003136 // Get the manifest from the current revision; revision is
3137 // base zero so subtract one from the count to get the
3138 // current revision.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00003139 Map headerMap = ba.getRevision(ba.getRevisionCount() - 1).getManifestHeader();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003140 // Get the activator class attribute.
3141 String className = (String) headerMap.get(Constants.BUNDLE_ACTIVATOR);
3142 // Try to instantiate activator class if present.
3143 if (className != null)
3144 {
3145 className = className.trim();
Richard S. Hall6b5f96c2006-02-10 15:57:15 +00003146 Class clazz = info.getCurrentModule().getClass(className);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003147 if (clazz == null)
3148 {
3149 throw new BundleException("Not found: "
3150 + className);
3151 }
3152 activator = (BundleActivator) clazz.newInstance();
3153 }
3154 }
3155
3156 return activator;
3157 }
3158
3159 private void purgeBundle(BundleImpl bundle) throws Exception
3160 {
3161 // Acquire bundle lock.
3162 acquireBundleLock(bundle);
3163
3164 try
3165 {
3166 BundleInfo info = bundle.getInfo();
3167
3168 // In case of a refresh, then we want to physically
3169 // remove the bundle's modules from the module manager.
3170 // This is necessary for two reasons: 1) because
3171 // under Windows we won't be able to delete the bundle
3172 // because files might be left open in the resource
3173 // sources of its modules and 2) we want to make sure
3174 // that no references to old modules exist since they
3175 // will all be stale after the refresh. The only other
3176 // way to do this is to remove the bundle, but that
3177 // would be incorrect, because this is a refresh operation
3178 // and should not trigger bundle REMOVE events.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003179 IModule[] modules = info.getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003180 for (int i = 0; i < modules.length; i++)
3181 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003182 m_factory.removeModule(modules[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003183 }
3184
3185 // Purge all bundle revisions, but the current one.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00003186 m_cache.getArchive(info.getBundleId()).purge();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003187 }
3188 finally
3189 {
3190 // Always release the bundle lock.
3191 releaseBundleLock(bundle);
3192 }
3193 }
3194
3195 private void garbageCollectBundle(BundleImpl bundle) throws Exception
3196 {
3197 // CONCURRENCY NOTE: There is no reason to lock this bundle,
3198 // because this method is only called during shutdown or a
3199 // refresh operation and these are already guarded by locks.
3200
3201 // Remove the bundle's associated modules from
3202 // the module manager.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003203 IModule[] modules = bundle.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003204 for (int i = 0; i < modules.length; i++)
3205 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003206 m_factory.removeModule(modules[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003207 }
3208
3209 // Remove the bundle from the cache.
3210 m_cache.remove(m_cache.getArchive(bundle.getInfo().getBundleId()));
3211 }
3212
3213 //
3214 // Event-related methods.
3215 //
3216
3217 /**
3218 * Fires bundle events.
3219 **/
3220 private void fireFrameworkEvent(
3221 int type, Bundle bundle, Throwable throwable)
3222 {
3223 if (m_frameworkDispatcher == null)
3224 {
3225 m_frameworkDispatcher = new Dispatcher() {
3226 public void dispatch(EventListener l, EventObject eventObj)
3227 {
3228 ((FrameworkListener) l)
3229 .frameworkEvent((FrameworkEvent) eventObj);
3230 }
3231 };
3232 }
3233 FrameworkEvent event = new FrameworkEvent(type, bundle, throwable);
3234 m_dispatchQueue.dispatch(
3235 m_frameworkDispatcher, FrameworkListener.class, event);
3236 }
3237
3238 /**
3239 * Fires bundle events.
3240 *
3241 * @param type The type of bundle event to fire.
3242 * @param bundle The bundle associated with the event.
3243 **/
3244 private void fireBundleEvent(int type, Bundle bundle)
3245 {
3246 if (m_bundleDispatcher == null)
3247 {
3248 m_bundleDispatcher = new Dispatcher() {
3249 public void dispatch(EventListener l, EventObject eventObj)
3250 {
3251 ((BundleListener) l)
3252 .bundleChanged((BundleEvent) eventObj);
3253 }
3254 };
3255 }
3256 BundleEvent event = null;
3257 event = new BundleEvent(type, bundle);
3258 m_dispatchQueue.dispatch(m_bundleDispatcher,
3259 BundleListener.class, event);
3260 }
3261
3262 /**
3263 * Fires service events.
3264 *
3265 * @param type The type of service event to fire.
3266 * @param ref The service reference associated with the event.
3267 **/
3268 private void fireServiceEvent(ServiceEvent event)
3269 {
3270 if (m_serviceDispatcher == null)
3271 {
3272 m_serviceDispatcher = new Dispatcher() {
3273 public void dispatch(EventListener l, EventObject eventObj)
3274 {
3275// TODO: Filter service events based on service permissions.
3276 if (l instanceof ListenerWrapper)
3277 {
3278 BundleImpl bundle = (BundleImpl) ((ServiceListenerWrapper) l).getBundle();
3279 if (isServiceAssignable(bundle, ((ServiceEvent) eventObj).getServiceReference()))
3280 {
3281 ((ServiceListener) l)
3282 .serviceChanged((ServiceEvent) eventObj);
3283 }
3284 }
3285 else
3286 {
3287 ((ServiceListener) l)
3288 .serviceChanged((ServiceEvent) eventObj);
3289 }
3290 }
3291 };
3292 }
3293 m_dispatchQueue.dispatch(m_serviceDispatcher,
3294 ServiceListener.class, event);
3295 }
3296
3297 //
3298 // Property related methods.
3299 //
3300
3301 private void initializeFrameworkProperties()
3302 {
3303 // Standard OSGi properties.
Richard S. Hallea415752005-12-05 19:30:28 +00003304 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003305 FelixConstants.FRAMEWORK_VERSION,
3306 FelixConstants.FRAMEWORK_VERSION_VALUE);
Richard S. Hallea415752005-12-05 19:30:28 +00003307 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003308 FelixConstants.FRAMEWORK_VENDOR,
3309 FelixConstants.FRAMEWORK_VENDOR_VALUE);
Richard S. Hallea415752005-12-05 19:30:28 +00003310 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003311 FelixConstants.FRAMEWORK_LANGUAGE,
3312 System.getProperty("user.language"));
Richard S. Hallea415752005-12-05 19:30:28 +00003313 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003314 FelixConstants.FRAMEWORK_OS_VERSION,
3315 System.getProperty("os.version"));
3316
3317 String s = null;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003318 s = R4Library.normalizePropertyValue(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003319 FelixConstants.FRAMEWORK_OS_NAME,
3320 System.getProperty("os.name"));
Richard S. Hallea415752005-12-05 19:30:28 +00003321 m_configMutable.put(FelixConstants.FRAMEWORK_OS_NAME, s);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003322 s = R4Library.normalizePropertyValue(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003323 FelixConstants.FRAMEWORK_PROCESSOR,
3324 System.getProperty("os.arch"));
Richard S. Hallea415752005-12-05 19:30:28 +00003325 m_configMutable.put(FelixConstants.FRAMEWORK_PROCESSOR, s);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003326
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003327
Richard S. Hallea415752005-12-05 19:30:28 +00003328 m_configMutable.put(
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003329 FelixConstants.FELIX_VERSION_PROPERTY, getVersion() );
Richard S. Hall930fecc2005-08-16 18:33:34 +00003330 }
3331
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003332
3333 private static final String FELIX_VERSION_VALUE;
3334
3335 static
3336 {
3337 FELIX_VERSION_VALUE = getVersion0();
3338 }
3339
3340
3341 private static String getVersion0()
3342 {
3343 // The framework version property.
3344 Properties props = new Properties();
3345 InputStream in = Felix.class.getResourceAsStream( "Felix.properties" );
3346 try
3347 {
3348 props.load( in );
3349 }
3350 catch ( IOException e )
3351 {
3352 e.printStackTrace();
3353 }
3354
3355 return props.getProperty( FelixConstants.FELIX_VERSION_PROPERTY, "unknown" );
3356 }
3357
3358
3359 public static String getVersion()
3360 {
3361 return FELIX_VERSION_VALUE;
3362 }
3363
3364
Richard S. Hall930fecc2005-08-16 18:33:34 +00003365 private void processAutoProperties()
3366 {
3367 // The auto-install property specifies a space-delimited list of
3368 // bundle URLs to be automatically installed into each new profile;
3369 // the start level to which the bundles are assigned is specified by
3370 // appending a ".n" to the auto-install property name, where "n" is
3371 // the desired start level for the list of bundles.
3372 String[] keys = m_config.getKeys();
3373 for (int i = 0; (keys != null) && (i < keys.length); i++)
3374 {
3375 if (keys[i].startsWith(FelixConstants.AUTO_INSTALL_PROP))
3376 {
3377 int startLevel = 1;
3378 try
3379 {
3380 startLevel = Integer.parseInt(keys[i].substring(keys[i].lastIndexOf('.') + 1));
3381 }
3382 catch (NumberFormatException ex)
3383 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003384 m_logger.log(Logger.LOG_ERROR, "Invalid property: " + keys[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003385 }
3386 StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
3387 if (st.countTokens() > 0)
3388 {
3389 String location = null;
3390 do
3391 {
3392 location = nextLocation(st);
3393 if (location != null)
3394 {
3395 try
3396 {
3397 BundleImpl b = (BundleImpl) installBundle(location, null);
3398 b.getInfo().setStartLevel(startLevel);
3399 }
3400 catch (Exception ex)
3401 {
3402 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003403 Logger.LOG_ERROR, "Auto-properties install.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003404 }
3405 }
3406 }
3407 while (location != null);
3408 }
3409 }
3410 }
3411
3412 // The auto-start property specifies a space-delimited list of
3413 // bundle URLs to be automatically installed and started into each
3414 // new profile; the start level to which the bundles are assigned
3415 // is specified by appending a ".n" to the auto-start property name,
3416 // where "n" is the desired start level for the list of bundles.
3417 // The following code starts bundles in two passes, first it installs
3418 // them, then it starts them.
3419 for (int i = 0; (keys != null) && (i < keys.length); i++)
3420 {
3421 if (keys[i].startsWith(FelixConstants.AUTO_START_PROP))
3422 {
3423 int startLevel = 1;
3424 try
3425 {
3426 startLevel = Integer.parseInt(keys[i].substring(keys[i].lastIndexOf('.') + 1));
3427 }
3428 catch (NumberFormatException ex)
3429 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003430 m_logger.log(Logger.LOG_ERROR, "Invalid property: " + keys[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003431 }
3432 StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
3433 if (st.countTokens() > 0)
3434 {
3435 String location = null;
3436 do
3437 {
3438 location = nextLocation(st);
3439 if (location != null)
3440 {
3441 try
3442 {
3443 BundleImpl b = (BundleImpl) installBundle(location, null);
3444 b.getInfo().setStartLevel(startLevel);
3445 }
3446 catch (Exception ex)
3447 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003448 m_logger.log(Logger.LOG_ERROR, "Auto-properties install.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003449 }
3450 }
3451 }
3452 while (location != null);
3453 }
3454 }
3455 }
3456
3457 // Now loop through and start the installed bundles.
3458 for (int i = 0; (keys != null) && (i < keys.length); i++)
3459 {
3460 if (keys[i].startsWith(FelixConstants.AUTO_START_PROP))
3461 {
3462 StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
3463 if (st.countTokens() > 0)
3464 {
3465 String location = null;
3466 do
3467 {
3468 location = nextLocation(st);
3469 if (location != null)
3470 {
3471 // Installing twice just returns the same bundle.
3472 try
3473 {
3474 BundleImpl bundle = (BundleImpl) installBundle(location, null);
3475 if (bundle != null)
3476 {
3477 startBundle(bundle, true);
3478 }
3479 }
3480 catch (Exception ex)
3481 {
3482 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003483 Logger.LOG_ERROR, "Auto-properties start.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003484 }
3485 }
3486 }
3487 while (location != null);
3488 }
3489 }
3490 }
3491 }
3492
3493 private String nextLocation(StringTokenizer st)
3494 {
3495 String retVal = null;
3496
3497 if (st.countTokens() > 0)
3498 {
3499 String tokenList = "\" ";
3500 StringBuffer tokBuf = new StringBuffer(10);
3501 String tok = null;
3502 boolean inQuote = false;
3503 boolean tokStarted = false;
3504 boolean exit = false;
3505 while ((st.hasMoreTokens()) && (!exit))
3506 {
3507 tok = st.nextToken(tokenList);
3508 if (tok.equals("\""))
3509 {
3510 inQuote = ! inQuote;
3511 if (inQuote)
3512 {
3513 tokenList = "\"";
3514 }
3515 else
3516 {
3517 tokenList = "\" ";
3518 }
3519
3520 }
3521 else if (tok.equals(" "))
3522 {
3523 if (tokStarted)
3524 {
3525 retVal = tokBuf.toString();
3526 tokStarted=false;
3527 tokBuf = new StringBuffer(10);
3528 exit = true;
3529 }
3530 }
3531 else
3532 {
3533 tokStarted = true;
3534 tokBuf.append(tok.trim());
3535 }
3536 }
3537
3538 // Handle case where end of token stream and
3539 // still got data
3540 if ((!exit) && (tokStarted))
3541 {
3542 retVal = tokBuf.toString();
3543 }
3544 }
3545
3546 return retVal;
3547 }
3548
3549 //
3550 // Private utility methods.
3551 //
3552
3553 /**
3554 * Generated the next valid bundle identifier.
3555 **/
Richard S. Hall441c7152006-02-17 11:07:10 +00003556 private long getNextId()
Richard S. Hall930fecc2005-08-16 18:33:34 +00003557 {
Richard S. Hall441c7152006-02-17 11:07:10 +00003558 synchronized (m_nextIdLock)
3559 {
3560 return m_nextId++;
3561 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003562 }
3563
3564 //
3565 // Configuration methods and inner classes.
3566 //
3567
3568 public PropertyResolver getConfig()
3569 {
3570 return m_config;
3571 }
3572
3573 private class ConfigImpl implements PropertyResolver
3574 {
3575 public String get(String key)
3576 {
Richard S. Hallea415752005-12-05 19:30:28 +00003577 return (m_configMutable == null) ? null : m_configMutable.get(key);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003578 }
3579
3580 public String[] getKeys()
3581 {
Richard S. Hallea415752005-12-05 19:30:28 +00003582 return m_configMutable.getKeys();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003583 }
3584 }
3585
3586 //
3587 // Logging methods and inner classes.
3588 //
3589
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003590 public Logger getLogger()
Richard S. Hall930fecc2005-08-16 18:33:34 +00003591 {
3592 return m_logger;
3593 }
3594
3595 /**
3596 * Simple class that is used in <tt>refreshPackages()</tt> to embody
3597 * the refresh logic in order to keep the code clean. This class is
3598 * not static because it needs access to framework event firing methods.
3599 **/
3600 private class RefreshHelper
3601 {
3602 private BundleImpl m_bundle = null;
3603
3604 public RefreshHelper(Bundle bundle)
3605 {
3606 m_bundle = (BundleImpl) bundle;
3607 }
3608
3609 public void stop()
3610 {
3611 if (m_bundle.getInfo().getState() == Bundle.ACTIVE)
3612 {
3613 try
3614 {
3615 stopBundle(m_bundle, false);
3616 }
3617 catch (BundleException ex)
3618 {
3619 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3620 }
3621 }
3622 }
3623
3624 public void purgeOrRemove()
3625 {
3626 try
3627 {
3628 BundleInfo info = m_bundle.getInfo();
3629
3630 // Remove or purge the bundle depending on its
3631 // current state.
3632 if (info.getState() == Bundle.UNINSTALLED)
3633 {
3634 // This physically removes the bundle from memory
3635 // as well as the bundle cache.
3636 garbageCollectBundle(m_bundle);
3637 m_bundle = null;
3638 }
3639 else
3640 {
3641 // This physically removes all old revisions of the
3642 // bundle from memory and only maintains the newest
3643 // version in the bundle cache.
3644 purgeBundle(m_bundle);
3645 }
3646 }
3647 catch (Exception ex)
3648 {
3649 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3650 }
3651 }
3652
3653 public void reinitialize()
3654 {
3655 if (m_bundle != null)
3656 {
3657 try
3658 {
3659 BundleInfo info = m_bundle.getInfo();
3660 BundleInfo newInfo = createBundleInfo(info.getArchive());
3661 newInfo.syncLock(info);
3662 m_bundle.setInfo(newInfo);
3663 }
3664 catch (Exception ex)
3665 {
3666 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3667 }
3668 }
3669 }
3670
3671 public void restart()
3672 {
3673 if (m_bundle != null)
3674 {
3675 try
3676 {
3677 startBundle(m_bundle, false);
3678 }
3679 catch (BundleException ex)
3680 {
3681 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3682 }
3683 }
3684 }
3685 }
3686
3687 //
3688 // Locking related methods.
3689 //
3690
3691 private void rememberUninstalledBundle(BundleImpl bundle)
3692 {
3693 synchronized (m_uninstalledBundlesLock_Priority3)
3694 {
3695 // Verify that the bundle is not already in the array.
3696 for (int i = 0;
3697 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
3698 i++)
3699 {
3700 if (m_uninstalledBundles[i] == bundle)
3701 {
3702 return;
3703 }
3704 }
3705
3706 if (m_uninstalledBundles != null)
3707 {
3708 BundleImpl[] newBundles =
3709 new BundleImpl[m_uninstalledBundles.length + 1];
3710 System.arraycopy(m_uninstalledBundles, 0,
3711 newBundles, 0, m_uninstalledBundles.length);
3712 newBundles[m_uninstalledBundles.length] = bundle;
3713 m_uninstalledBundles = newBundles;
3714 }
3715 else
3716 {
3717 m_uninstalledBundles = new BundleImpl[] { bundle };
3718 }
3719 }
3720 }
3721
3722 private void forgetUninstalledBundle(BundleImpl bundle)
3723 {
3724 synchronized (m_uninstalledBundlesLock_Priority3)
3725 {
3726 if (m_uninstalledBundles == null)
3727 {
3728 return;
3729 }
3730
3731 int idx = -1;
3732 for (int i = 0; i < m_uninstalledBundles.length; i++)
3733 {
3734 if (m_uninstalledBundles[i] == bundle)
3735 {
3736 idx = i;
3737 break;
3738 }
3739 }
3740
3741 if (idx >= 0)
3742 {
3743 // If this is the only bundle, then point to empty list.
3744 if ((m_uninstalledBundles.length - 1) == 0)
3745 {
3746 m_uninstalledBundles = new BundleImpl[0];
3747 }
3748 // Otherwise, we need to do some array copying.
3749 else
3750 {
3751 BundleImpl[] newBundles =
3752 new BundleImpl[m_uninstalledBundles.length - 1];
3753 System.arraycopy(m_uninstalledBundles, 0, newBundles, 0, idx);
3754 if (idx < newBundles.length)
3755 {
3756 System.arraycopy(
3757 m_uninstalledBundles, idx + 1,
3758 newBundles, idx, newBundles.length - idx);
3759 }
3760 m_uninstalledBundles = newBundles;
3761 }
3762 }
3763 }
3764 }
3765
3766 protected void acquireInstallLock(String location)
3767 throws BundleException
3768 {
3769 synchronized (m_installRequestLock_Priority1)
3770 {
3771 while (m_installRequestMap.get(location) != null)
3772 {
3773 try
3774 {
3775 m_installRequestLock_Priority1.wait();
3776 }
3777 catch (InterruptedException ex)
3778 {
3779 throw new BundleException("Unable to install, thread interrupted.");
3780 }
3781 }
3782
3783 m_installRequestMap.put(location, location);
3784 }
3785 }
3786
3787 protected void releaseInstallLock(String location)
3788 {
3789 synchronized (m_installRequestLock_Priority1)
3790 {
3791 m_installRequestMap.remove(location);
3792 m_installRequestLock_Priority1.notifyAll();
3793 }
3794 }
3795
3796 protected void acquireBundleLock(BundleImpl bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003797 {
3798 synchronized (m_bundleLock)
3799 {
3800 while (!bundle.getInfo().isLockable())
3801 {
3802 try
3803 {
3804 m_bundleLock.wait();
3805 }
3806 catch (InterruptedException ex)
3807 {
3808 // Ignore and just keep waiting.
3809 }
3810 }
3811 bundle.getInfo().lock();
3812 }
3813 }
3814
Richard S. Hall3c26cc02006-02-17 13:51:21 +00003815 protected boolean acquireBundleLockOrFail(BundleImpl bundle)
3816 {
3817 synchronized (m_bundleLock)
3818 {
3819 if (!bundle.getInfo().isLockable())
3820 {
3821 return false;
3822 }
3823 bundle.getInfo().lock();
3824 return true;
3825 }
3826 }
3827
Richard S. Hall930fecc2005-08-16 18:33:34 +00003828 protected void releaseBundleLock(BundleImpl bundle)
3829 {
3830 synchronized (m_bundleLock)
3831 {
3832 bundle.getInfo().unlock();
3833 m_bundleLock.notifyAll();
3834 }
3835 }
3836
3837 protected BundleImpl[] acquireBundleRefreshLocks(Bundle[] targets)
3838 {
3839 // Hold bundles to be locked.
3840 BundleImpl[] bundles = null;
3841
3842 synchronized (m_bundleLock)
3843 {
3844 boolean success = false;
3845 while (!success)
3846 {
3847 // If targets is null, then refresh all pending bundles.
3848 Bundle[] newTargets = targets;
3849 if (newTargets == null)
3850 {
3851 List list = new ArrayList();
3852
3853 // First add all uninstalled bundles.
3854 synchronized (m_uninstalledBundlesLock_Priority3)
3855 {
3856 for (int i = 0;
3857 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
3858 i++)
3859 {
3860 list.add(m_uninstalledBundles[i]);
3861 }
3862 }
3863
3864 // Then add all updated bundles.
3865 synchronized (m_installedBundleLock_Priority2)
3866 {
3867 Iterator iter = m_installedBundleMap.values().iterator();
3868 while (iter.hasNext())
3869 {
3870 BundleImpl bundle = (BundleImpl) iter.next();
3871 if (bundle.getInfo().isRemovalPending())
3872 {
3873 list.add(bundle);
3874 }
3875 }
3876 }
3877
3878 // Create an array.
3879 if (list.size() > 0)
3880 {
3881 newTargets = (Bundle[]) list.toArray(new Bundle[list.size()]);
3882 }
3883 }
3884
3885 // If there are targets, then find all dependencies
3886 // for each one.
3887 if (newTargets != null)
3888 {
3889 // Create map of bundles that import the packages
3890 // from the target bundles.
3891 Map map = new HashMap();
3892 for (int targetIdx = 0; targetIdx < newTargets.length; targetIdx++)
3893 {
3894 // Add the current target bundle to the map of
3895 // bundles to be refreshed.
3896 BundleImpl target = (BundleImpl) newTargets[targetIdx];
3897 map.put(target, target);
3898 // Add all importing bundles to map.
3899 populateImportGraph(target, map);
3900 }
3901
3902 bundles = (BundleImpl[]) map.values().toArray(new BundleImpl[map.size()]);
3903 }
3904
3905 // Check if all corresponding bundles can be locked
3906 boolean lockable = true;
3907 if (bundles != null)
3908 {
3909 for (int i = 0; lockable && (i < bundles.length); i++)
3910 {
3911 lockable = bundles[i].getInfo().isLockable();
3912 }
3913
3914 // If we can lock all bundles, then lock them.
3915 if (lockable)
3916 {
3917 for (int i = 0; i < bundles.length; i++)
3918 {
3919 bundles[i].getInfo().lock();
3920 }
3921 success = true;
3922 }
3923 // Otherwise, wait and try again.
3924 else
3925 {
3926 try
3927 {
3928 m_bundleLock.wait();
3929 }
3930 catch (InterruptedException ex)
3931 {
3932 // Ignore and just keep waiting.
3933 }
3934 }
3935 }
3936 else
3937 {
3938 // If there were no bundles to lock, then we can just
3939 // exit the lock loop.
3940 success = true;
3941 }
3942 }
3943 }
3944
3945 return bundles;
3946 }
3947
3948 protected void releaseBundleLocks(BundleImpl[] bundles)
3949 {
3950 // Always unlock any locked bundles.
3951 synchronized (m_bundleLock)
3952 {
3953 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
3954 {
3955 bundles[i].getInfo().unlock();
3956 }
3957 m_bundleLock.notifyAll();
3958 }
3959 }
Richard S. Hall9a3e9852006-03-04 03:44:05 +00003960}