blob: d623b9b7c2be8fcaf51a7e0deef298e8cf0f2f80 [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. Hall04bdbb12006-03-15 14:26:15 +000084 private BundleCache 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>
Richard S. Hall930fecc2005-08-16 18:33:34 +0000134 * <li><tt>felix.auto.install.&lt;n&gt;</tt> - Space-delimited list of
135 * bundles to automatically install into start level <tt>n</tt> when
136 * the framework is started. Append a specific start level to this
137 * property name to assign the bundles' start level
138 * (e.g., <tt>felix.auto.install.2</tt>).
139 * </li>
140 * <li><tt>felix.auto.start.&lt;n&gt;</tt> - Space-delimited list of
141 * bundles to automatically install and start into start level
142 * <tt>n</tt> when the framework is started. Append a
143 * specific start level to this property name to assign the
144 * bundles' start level(e.g., <tt>felix.auto.start.2</tt>).
145 * </li>
146 * <li><tt>felix.startlevel.framework</tt> - The initial start level
147 * of the framework once it starts execution; the default
148 * value is 1.
149 * </li>
150 * <li><tt>felix.startlevel.bundle</tt> - The default start level for
151 * newly installed bundles; the default value is 1.
152 * </li>
Richard S. Hall5d226732005-11-08 09:09:05 +0000153 * <li><tt>framework.service.urlhandlers</tt> - Flag to indicate whether
154 * to activate the URL Handlers service for the framework instance;
155 * the default value is "<tt>true</tt>". Activating the URL Handlers
156 * service will result in the <tt>URL.setURLStreamHandlerFactory()</tt>
157 * and <tt>URLConnection.setContentHandlerFactory()</tt> being called.
158 * </li>
Richard S. Hall930fecc2005-08-16 18:33:34 +0000159 * <li><tt>felix.embedded.execution</tt> - Flag to indicate whether
160 * the framework is embedded into a host application; the default value is
161 * "<tt>false</tt>". If this flag is "<tt>true</tt>" then the framework
162 * will not called <tt>System.exit()</tt> upon termination.
163 * </li>
164 * <li><tt>felix.strict.osgi</tt> - Flag to indicate whether the framework is
165 * running in strict OSGi mode; the default value is "<tt>true</tt>".
166 * If this flag is "<tt>false</tt>" it enables a non-OSGi-compliant
167 * feature by persisting <tt>BundleActivator</tt>s that implement
168 * <tt>Serializable</tt>. This feature is not recommended since
169 * it is non-compliant.
170 * </li>
171 * </ul>
172 * <p>
173 * Besides the above framework configuration properties, it is also
174 * possible to specify properties for the bundle cache. The available
175 * bundle cache properties depend on the cache implementation
176 * being used. For the properties of the default bundle cache, refer to the
177 * <a href="cache/DefaultBundleCache.html"><tt>DefaulBundleCache</tt></a>
178 * API documentation.
179 * </p>
180 * <p>
181 * Framework properties are somewhat misnamed, since they are not used by
182 * the framework, but by bundles via <tt>BundleContext.getProperty()</tt>.
183 * Please refer to bundle documentation of your specific bundle for any
184 * available properties.
185 * </p>
186 * <p>
187 * The <a href="Main.html"><tt>Main</tt></a> class implements some
188 * functionality for default property file handling, which makes it
189 * possible to specify configuration properties and framework properties
190 * in files that are automatically loaded when starting the framework. If you
191 * plan to create your own framework instance, you may be
192 * able to take advantage of the features it provides; refer to its
193 * class documentation for more information.
194 * </p>
195 *
Richard S. Hallea415752005-12-05 19:30:28 +0000196 * @param configMutable An object for obtaining configuration properties,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000197 * may be <tt>null</tt>.
198 * @param frameworkProps An object for obtaining framework properties,
199 * may be <tt>null</tt>.
200 * @param activatorList A list of System Bundle activators.
201 **/
202 public synchronized void start(
Richard S. Hallea415752005-12-05 19:30:28 +0000203 MutablePropertyResolver configMutable,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000204 List activatorList)
205 {
206 if (m_frameworkStatus != INITIAL_STATUS)
207 {
208 throw new IllegalStateException("Invalid framework status: " + m_frameworkStatus);
209 }
210
211 // The framework is now in its startup sequence.
212 m_frameworkStatus = STARTING_STATUS;
213
214 // Initialize member variables.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000215 m_factory = null;
Richard S. Hallea415752005-12-05 19:30:28 +0000216 m_configMutable = (configMutable == null)
217 ? new MutablePropertyResolverImpl(new StringMap(false)) : configMutable;
Richard S. Hall930fecc2005-08-16 18:33:34 +0000218 m_activeStartLevel = FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
219 m_installRequestMap = new HashMap();
220 m_installedBundleMap = new HashMap();
221 m_uninstalledBundles = null;
222 m_cache = null;
223 m_nextId = 1L;
224 m_dispatchQueue = null;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000225 m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000226 m_registry = new ServiceRegistry(m_logger);
227
228 // Add a listener to the service registry; this is
229 // used to distribute service registry events to
230 // service listeners.
231 m_registry.addServiceListener(new ServiceListener() {
232 public void serviceChanged(ServiceEvent event)
233 {
234 fireServiceEvent(event);
235 }
236 });
237
Richard S. Hall930fecc2005-08-16 18:33:34 +0000238 try
239 {
Richard S. Hall04bdbb12006-03-15 14:26:15 +0000240 m_cache = new BundleCache(m_config, m_logger);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000241 }
242 catch (Exception ex)
243 {
244 System.err.println("Error creating bundle cache:");
245 ex.printStackTrace();
246
247 // Only shutdown the JVM if the framework is running stand-alone.
248 String embedded = m_config.get(
249 FelixConstants.EMBEDDED_EXECUTION_PROP);
250 boolean isEmbedded = (embedded == null)
251 ? false : embedded.equals("true");
252 if (!isEmbedded)
253 {
254 System.exit(-1);
255 }
256 else
257 {
258 throw new RuntimeException(ex.toString());
259 }
260 }
261
262 // Create search policy for module loader.
Richard S. Halle975d4d2006-04-10 12:56:14 +0000263 m_policyCore = new R4SearchPolicyCore(m_logger, m_config);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000264
265 // Add a resolver listener to the search policy
266 // so that we will be notified when modules are resolved
267 // in order to update the bundle state.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000268 m_policyCore.addResolverListener(new ResolveListener() {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000269 public void moduleResolved(ModuleEvent event)
270 {
271 BundleImpl bundle = null;
272 try
273 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000274 long id = Util.getBundleIdFromModuleId(
Richard S. Hall930fecc2005-08-16 18:33:34 +0000275 event.getModule().getId());
276 if (id >= 0)
277 {
278 // Update the bundle's state to resolved when the
279 // current module is resolved; just ignore resolve
280 // events for older revisions since this only occurs
281 // when an update is done on an unresolved bundle
282 // and there was no refresh performed.
283 bundle = (BundleImpl) getBundle(id);
284
285 // Lock the bundle first.
286 try
287 {
288 acquireBundleLock(bundle);
289 if (bundle.getInfo().getCurrentModule() == event.getModule())
290 {
291 bundle.getInfo().setState(Bundle.RESOLVED);
292 }
293 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000294 finally
295 {
296 releaseBundleLock(bundle);
297 }
298 }
299 }
300 catch (NumberFormatException ex)
301 {
302 // Ignore.
303 }
304 }
305
306 public void moduleUnresolved(ModuleEvent event)
307 {
308 // We can ignore this, because the only time it
309 // should happen is when a refresh occurs. The
310 // refresh operation resets the bundle's state
311 // by calling BundleInfo.reset(), thus it is not
312 // necessary for us to reset the bundle's state
313 // here.
314 }
315 });
316
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000317 m_factory = new ModuleFactoryImpl(m_logger);
318 m_policyCore.setModuleFactory(m_factory);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000319
320 // Initialize dispatch queue.
321 m_dispatchQueue = new FelixDispatchQueue(m_logger);
322
323 // Initialize framework properties.
324 initializeFrameworkProperties();
325
326 // Before we reload any cached bundles, let's create a system
327 // bundle that is responsible for providing specific container
328 // related services.
329 SystemBundle systembundle = null;
330 try
331 {
332 // Create a simple bundle info for the system bundle.
333 BundleInfo info = new BundleInfo(
334 m_logger, new SystemBundleArchive(), null);
335 systembundle = new SystemBundle(this, info, activatorList);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000336 systembundle.getInfo().addModule(m_factory.createModule("0"));
337 systembundle.getContentLoader().setSearchPolicy(
338 new R4SearchPolicy(
339 m_policyCore, systembundle.getInfo().getCurrentModule()));
340 m_factory.setContentLoader(
341 systembundle.getInfo().getCurrentModule(),
342 systembundle.getContentLoader());
343 m_policyCore.setExports(
344 systembundle.getInfo().getCurrentModule(), systembundle.getExports());
345
Richard S. Hall930fecc2005-08-16 18:33:34 +0000346 m_installedBundleMap.put(
347 systembundle.getInfo().getLocation(), systembundle);
348
349 // Manually resolve the System Bundle, which will cause its
350 // state to be set to RESOLVED.
351 try
352 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000353 m_policyCore.resolve(systembundle.getInfo().getCurrentModule());
Richard S. Hall930fecc2005-08-16 18:33:34 +0000354 }
355 catch (ResolveException ex)
356 {
357 // This should never happen.
358 throw new BundleException(
359 "Unresolved package in System Bundle:"
360 + ex.getPackage());
361 }
362
363 // Start the system bundle; this will set its state
364 // to STARTING, we must set its state to ACTIVE after
365 // all bundles are restarted below according to the spec.
366 systembundle.start();
367 }
368 catch (Exception ex)
369 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000370 m_factory = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +0000371 DispatchQueue.shutdown();
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000372 m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000373 throw new RuntimeException("Unable to start system bundle.");
374 }
375
376 // Reload and cached bundles.
Richard S. Hall04bdbb12006-03-15 14:26:15 +0000377 BundleArchive[] archives = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +0000378
379 // First get cached bundle identifiers.
380 try
381 {
382 archives = m_cache.getArchives();
383 }
384 catch (Exception ex)
385 {
386 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000387 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000388 "Unable to list saved bundles: " + ex, ex);
389 archives = null;
390 }
391
392 BundleImpl bundle = null;
393
394 // Now install all cached bundles.
395 for (int i = 0; (archives != null) && (i < archives.length); i++)
396 {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000397 try
398 {
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000399 // Make sure our id generator is not going to overlap.
400 // TODO: This is not correct since it may lead to re-used
401 // ids, which is not okay according to OSGi.
402 m_nextId = Math.max(m_nextId, archives[i].getId() + 1);
403
Richard S. Hall930fecc2005-08-16 18:33:34 +0000404 // It is possible that a bundle in the cache was previously
405 // uninstalled, but not completely deleted (perhaps because
406 // of a crash or a locked file), so if we see an archive
407 // with an UNINSTALLED persistent state, then try to remove
408 // it now.
409 if (archives[i].getPersistentState() == Bundle.UNINSTALLED)
410 {
411 m_cache.remove(archives[i]);
412 }
413 // Otherwise re-install the cached bundle.
414 else
415 {
416 // Install the cached bundle.
417 bundle = (BundleImpl) installBundle(
418 archives[i].getId(), archives[i].getLocation(), null);
419 }
420 }
421 catch (Exception ex)
422 {
423 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
424 try
425 {
426 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000427 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000428 "Unable to re-install " + archives[i].getLocation(),
429 ex);
430 }
431 catch (Exception ex2)
432 {
433 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000434 Logger.LOG_ERROR,
Richard S. Hall7c9da3d2006-02-24 20:09:28 +0000435 "Unable to re-install cached bundle.",
Richard S. Hall930fecc2005-08-16 18:33:34 +0000436 ex);
437 }
438 // TODO: Perhaps we should remove the cached bundle?
439 }
440 }
441
442 // Get the framework's default start level.
443 int startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
444 String s = m_config.get(FelixConstants.FRAMEWORK_STARTLEVEL_PROP);
445 if (s != null)
446 {
447 try
448 {
449 startLevel = Integer.parseInt(s);
450 }
451 catch (NumberFormatException ex)
452 {
453 startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
454 }
455 }
456
457 // Load bundles from auto-install and auto-start properties;
458 processAutoProperties();
459
Richard S. Hall17897152006-03-02 13:43:09 +0000460 // Set the start level using the start level service;
461 // this ensures that all start level requests are
462 // serialized.
463 // NOTE: There is potentially a specification compliance
464 // issue here, since the start level request is asynchronous;
465 // this means that the framework will fire its STARTED event
466 // before all bundles have officially been restarted and it
467 // is not clear if this is really an issue or not.
468 try
469 {
470 StartLevel sl = (StartLevel) getService(
471 getBundle(0),
472 getServiceReferences((BundleImpl) getBundle(0), StartLevel.class.getName(), null)[0]);
473 sl.setStartLevel(startLevel);
474 }
475 catch (InvalidSyntaxException ex)
476 {
477 // Should never happen.
478 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000479
480 // The framework is now running.
481 m_frameworkStatus = RUNNING_STATUS;
482
483 // Set the system bundle state to ACTIVE.
484 systembundle.getInfo().setState(Bundle.ACTIVE);
485
486 // Fire started event for system bundle.
487 fireBundleEvent(BundleEvent.STARTED, systembundle);
488
489 // Send a framework event to indicate the framework has started.
490 fireFrameworkEvent(FrameworkEvent.STARTED, getBundle(0), null);
491 }
492
493 /**
494 * This method cleanly shuts down the framework, it must be called at the
495 * end of a session in order to shutdown all active bundles.
496 **/
497 public synchronized void shutdown()
498 {
499 if (System.getSecurityManager() != null)
500 {
501 AccessController.checkPermission(m_adminPerm);
502 }
503
504 // Change framework status from running to stopping.
505 // If framework is not running, then just return.
506 if (m_frameworkStatus != RUNNING_STATUS)
507 {
508 return;
509 }
510
511 // The framework is now in its shutdown sequence.
512 m_frameworkStatus = STOPPING_STATUS;
513
Richard S. Hall17897152006-03-02 13:43:09 +0000514 // Use the start level service to set the start level to zero
515 // in order to stop all bundles in the framework. Since framework
516 // shutdown happens on its own thread, we can wait for the start
517 // level service to finish before proceeding by calling the
518 // non-spec setStartLevelAndWait() method.
519 try
520 {
521 StartLevelImpl sl = (StartLevelImpl) getService(
522 getBundle(0),
523 getServiceReferences((BundleImpl) getBundle(0), StartLevel.class.getName(), null)[0]);
524 sl.setStartLevelAndWait(0);
525 }
526 catch (InvalidSyntaxException ex)
527 {
528 // Should never happen.
529 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000530
531 // Just like initialize() called the system bundle's start()
532 // method, we must call its stop() method here so that it
533 // can perform any necessary clean up.
534 try
535 {
536 getBundle(0).stop();
537 }
538 catch (Exception ex)
539 {
540 fireFrameworkEvent(FrameworkEvent.ERROR, getBundle(0), ex);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000541 m_logger.log(Logger.LOG_ERROR, "Error stopping system bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000542 }
543
Richard S. Hall60c26d42006-07-19 10:35:04 +0000544 // Since they may be updated and uninstalled bundles that
545 // have not been refreshed, we will take care of refreshing
546 // them during shutdown.
547
548 // First loop through all bundled and purge old revisions
549 // from updated bundles.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000550 Bundle[] bundles = getBundles();
551 for (int i = 0; i < bundles.length; i++)
552 {
553 BundleImpl bundle = (BundleImpl) bundles[i];
Richard S. Hall60c26d42006-07-19 10:35:04 +0000554 if (bundle.getInfo().getArchive().getRevisionCount() > 1)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000555 {
556 try
557 {
558 purgeBundle(bundle);
559 }
560 catch (Exception ex)
561 {
562 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000563 m_logger.log(Logger.LOG_ERROR, "Unable to purge bundle "
Richard S. Hall930fecc2005-08-16 18:33:34 +0000564 + bundle.getInfo().getLocation(), ex);
565 }
566 }
567 }
568
Richard S. Hall60c26d42006-07-19 10:35:04 +0000569 // Next garbage collection any uninstalled bundles.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000570 for (int i = 0;
571 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
572 i++)
573 {
574 try
575 {
576 garbageCollectBundle(m_uninstalledBundles[i]);
577 }
578 catch (Exception ex)
579 {
580 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000581 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000582 "Unable to remove "
583 + m_uninstalledBundles[i].getInfo().getLocation(), ex);
584 }
585 }
586
587 // Shutdown event dispatching queue.
588 DispatchQueue.shutdown();
589
590 // The framework is no longer in a usable state.
591 m_frameworkStatus = INITIAL_STATUS;
Richard S. Hall3331ad72006-06-20 09:07:23 +0000592
593 // Remove all bundles from the module factory so that any
594 // open resources will be closed.
595 bundles = getBundles();
596 for (int i = 0; i < bundles.length; i++)
597 {
598 BundleImpl bundle = (BundleImpl) bundles[i];
599 try
600 {
601 IModule[] modules = bundle.getInfo().getModules();
602 for (int j = 0; j < modules.length; j++)
603 {
604 m_factory.removeModule(modules[j]);
605 }
606 }
607 catch (Exception ex)
608 {
609 m_logger.log(Logger.LOG_ERROR,
610 "Unable to clean up " + bundle.getInfo().getLocation(), ex);
611 }
612 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000613 }
614
615 public int getStatus()
616 {
617 return m_frameworkStatus;
618 }
619
620 /**
621 * Returns the active start level of the framework; this method
622 * implements functionality for the Start Level service.
623 * @return The active start level of the framework.
624 **/
625 protected int getStartLevel()
626 {
627 return m_activeStartLevel;
628 }
629
630 /**
631 * Implements the functionality of the <tt>setStartLevel()</tt>
632 * method for the StartLevel service, but does not do the security or
633 * parameter check. The security and parameter check are done in the
634 * StartLevel service implementation because this method is called on
635 * a separate thread and the caller's thread would already be gone if
Richard S. Hall17897152006-03-02 13:43:09 +0000636 * we did the checks in this method. This method should not be called
637 * directly.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000638 * @param requestedLevel The new start level of the framework.
639 **/
Richard S. Hall441c7152006-02-17 11:07:10 +0000640 protected void setFrameworkStartLevel(int requestedLevel)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000641 {
Richard S. Hall17897152006-03-02 13:43:09 +0000642 Bundle[] bundles = null;
643
644 // Synchronization for changing the start level is rather loose.
645 // The install lock is grabbed initially to atomically change the
646 // framework's start level and to grab a sorted snapshot of the
647 // currently installed bundles, but then this lock is freed immediately.
648 // No locks are held while processing the currently installed bundles
649 // for starting/stopping based on the new start level. The only locking
650 // that occurs is for individual bundles when startBundle()/stopBundle()
651 // is called, but this locking is done in the respective method.
652 //
653 // This approach does mean that it is possible for a for individual
654 // bundle states to change during this operation. For example, bundle
655 // start levels can be changed or bundles can be uninstalled. If a
656 // bundle's start level changes, then it is possible for it to be
657 // processed out of order. Uninstalled bundles are just logged and
658 // ignored. I had a bit of discussion with Peter Kriens about these
659 // issues and he felt they were consistent with the spec, which
660 // intended Start Level to have some leeway.
661 //
662 // Calls to this method are only made by the start level thread, which
663 // serializes framework start level changes. Thus, it is not possible
664 // for two requests to change the framework's start level to interfere
665 // with each other.
666
667 synchronized (m_installedBundleLock_Priority2)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000668 {
Richard S. Hall17897152006-03-02 13:43:09 +0000669 // Determine if we are lowering or raising the
670 // active start level.
671 boolean lowering = (requestedLevel < m_activeStartLevel);
672
673 // Record new start level.
674 m_activeStartLevel = requestedLevel;
675
676 // Get a snapshot of all installed bundles.
677 bundles = getBundles();
678
679 // Sort bundle array by start level either ascending or
680 // descending depending on whether the start level is being
681 // lowered or raised to that the bundles can be efficiently
Richard S. Hall5259e3e2006-07-14 18:55:59 +0000682 // processed in order. Within a start level sort by bundle ID.
Richard S. Hall17897152006-03-02 13:43:09 +0000683 Comparator comparator = null;
684 if (lowering)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000685 {
Richard S. Hall17897152006-03-02 13:43:09 +0000686 // Sort descending to stop highest start level first.
687 comparator = new Comparator() {
688 public int compare(Object o1, Object o2)
Richard S. Hall441c7152006-02-17 11:07:10 +0000689 {
Richard S. Hall17897152006-03-02 13:43:09 +0000690 BundleImpl b1 = (BundleImpl) o1;
691 BundleImpl b2 = (BundleImpl) o2;
692 if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
693 < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
694 {
695 return 1;
696 }
697 else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
698 > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
699 {
700 return -1;
701 }
Richard S. Hall5259e3e2006-07-14 18:55:59 +0000702 else if (b1.getInfo().getBundleId() < b2.getInfo().getBundleId())
703 {
704 return 1;
705 }
706 return -1;
Richard S. Hall441c7152006-02-17 11:07:10 +0000707 }
Richard S. Hall17897152006-03-02 13:43:09 +0000708 };
709 }
710 else
711 {
712 // Sort ascending to start lowest start level first.
713 comparator = new Comparator() {
714 public int compare(Object o1, Object o2)
Richard S. Hall441c7152006-02-17 11:07:10 +0000715 {
Richard S. Hall17897152006-03-02 13:43:09 +0000716 BundleImpl b1 = (BundleImpl) o1;
717 BundleImpl b2 = (BundleImpl) o2;
718 if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
719 > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
Richard S. Hall441c7152006-02-17 11:07:10 +0000720 {
Richard S. Hall17897152006-03-02 13:43:09 +0000721 return 1;
Richard S. Hall441c7152006-02-17 11:07:10 +0000722 }
Richard S. Hall17897152006-03-02 13:43:09 +0000723 else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
724 < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
Richard S. Hall441c7152006-02-17 11:07:10 +0000725 {
Richard S. Hall17897152006-03-02 13:43:09 +0000726 return -1;
Richard S. Hall441c7152006-02-17 11:07:10 +0000727 }
Richard S. Hall5259e3e2006-07-14 18:55:59 +0000728 else if (b1.getInfo().getBundleId() > b2.getInfo().getBundleId())
729 {
730 return 1;
731 }
732 return -1;
Richard S. Hall17897152006-03-02 13:43:09 +0000733 }
734 };
735 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000736
Richard S. Hall17897152006-03-02 13:43:09 +0000737 Arrays.sort(bundles, comparator);
738 }
739
740 // Stop or start the bundles according to the start level.
741 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
742 {
743 BundleImpl impl = (BundleImpl) bundles[i];
744
745 // Ignore the system bundle, since its start() and
746 // stop() methods get called explicitly in Felix.start()
747 // and Felix.shutdown(), respectively.
748 if (impl.getInfo().getBundleId() == 0)
749 {
750 continue;
751 }
752
753 // Lock the current bundle.
754 acquireBundleLock(impl);
755
756 try
757 {
758 // Start the bundle if necessary.
759 if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
760 (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
761 <= m_activeStartLevel))
762 {
763 try
764 {
765 startBundle(impl, false);
766 }
767 catch (Throwable th)
768 {
769 fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
770 m_logger.log(
771 Logger.LOG_ERROR,
772 "Error starting " + impl.getInfo().getLocation(), th);
Richard S. Hall441c7152006-02-17 11:07:10 +0000773 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000774 }
Richard S. Hall17897152006-03-02 13:43:09 +0000775 // Stop the bundle if necessary.
776 else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
777 > m_activeStartLevel)
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000778 {
Richard S. Hall17897152006-03-02 13:43:09 +0000779 try
Richard S. Hall441c7152006-02-17 11:07:10 +0000780 {
Richard S. Hall17897152006-03-02 13:43:09 +0000781 stopBundle(impl, false);
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000782 }
Richard S. Hall17897152006-03-02 13:43:09 +0000783 catch (Throwable th)
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000784 {
Richard S. Hall17897152006-03-02 13:43:09 +0000785 fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
786 m_logger.log(
787 Logger.LOG_ERROR,
788 "Error stopping " + impl.getInfo().getLocation(), th);
Richard S. Hall441c7152006-02-17 11:07:10 +0000789 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000790 }
Richard S. Hall17897152006-03-02 13:43:09 +0000791 }
792 finally
793 {
794 // Always release bundle lock.
795 releaseBundleLock(impl);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000796 }
797 }
798
799 fireFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, getBundle(0), null);
800 }
801
802 /**
803 * Returns the start level into which newly installed bundles will
804 * be placed by default; this method implements functionality for
805 * the Start Level service.
806 * @return The default start level for newly installed bundles.
807 **/
808 protected int getInitialBundleStartLevel()
809 {
810 String s = m_config.get(FelixConstants.BUNDLE_STARTLEVEL_PROP);
811
812 if (s != null)
813 {
814 try
815 {
816 int i = Integer.parseInt(s);
817 return (i > 0) ? i : FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
818 }
819 catch (NumberFormatException ex)
820 {
821 // Ignore and return the default value.
822 }
823 }
824 return FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
825 }
826
827 /**
828 * Sets the default start level into which newly installed bundles
829 * will be placed; this method implements functionality for the Start
830 * Level service.
831 * @param startLevel The new default start level for newly installed
832 * bundles.
833 * @throws java.lang.IllegalArgumentException If the specified start
834 * level is not greater than zero.
835 * @throws java.security.SecurityException If the caller does not
836 * have <tt>AdminPermission</tt>.
837 **/
838 protected void setInitialBundleStartLevel(int startLevel)
839 {
840 if (System.getSecurityManager() != null)
841 {
842 AccessController.checkPermission(m_adminPerm);
843 }
844
845 if (startLevel <= 0)
846 {
847 throw new IllegalArgumentException(
848 "Initial start level must be greater than zero.");
849 }
850
Richard S. Hallea415752005-12-05 19:30:28 +0000851 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +0000852 FelixConstants.BUNDLE_STARTLEVEL_PROP, Integer.toString(startLevel));
853 }
854
855 /**
856 * Returns the start level for the specified bundle; this method
857 * implements functionality for the Start Level service.
858 * @param bundle The bundle to examine.
859 * @return The start level of the specified bundle.
860 * @throws java.lang.IllegalArgumentException If the specified
861 * bundle has been uninstalled.
862 **/
863 protected int getBundleStartLevel(Bundle bundle)
864 {
865 if (bundle.getState() == Bundle.UNINSTALLED)
866 {
867 throw new IllegalArgumentException("Bundle is uninstalled.");
868 }
869
870 return ((BundleImpl) bundle).getInfo().getStartLevel(getInitialBundleStartLevel());
871 }
872
873 /**
874 * Sets the start level of the specified bundle; this method
875 * implements functionality for the Start Level service.
876 * @param bundle The bundle whose start level is to be modified.
877 * @param startLevel The new start level of the specified bundle.
878 * @throws java.lang.IllegalArgumentException If the specified
879 * bundle is the system bundle or if the bundle has been
880 * uninstalled.
881 * @throws java.security.SecurityException If the caller does not
882 * have <tt>AdminPermission</tt>.
883 **/
884 protected void setBundleStartLevel(Bundle bundle, int startLevel)
885 {
Richard S. Hall930fecc2005-08-16 18:33:34 +0000886 // Acquire bundle lock.
Richard S. Hall3c26cc02006-02-17 13:51:21 +0000887 acquireBundleLock((BundleImpl) bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000888
889 Throwable rethrow = null;
890
891 try
892 {
893 if (bundle.getState() == Bundle.UNINSTALLED)
894 {
895 throw new IllegalArgumentException("Bundle is uninstalled.");
896 }
897
898 if (startLevel >= 1)
899 {
900 BundleImpl impl = (BundleImpl) bundle;
901 impl.getInfo().setStartLevel(startLevel);
902
903 try
904 {
905 // Start the bundle if necessary.
906 if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
907 (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
908 <= m_activeStartLevel))
909 {
910 startBundle(impl, false);
911 }
912 // Stop the bundle if necessary.
913 else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
914 > m_activeStartLevel)
915 {
916 stopBundle(impl, false);
917 }
918 }
919 catch (Throwable th)
920 {
921 rethrow = th;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000922 m_logger.log(Logger.LOG_ERROR, "Error starting/stopping bundle.", th);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000923 }
924 }
925 else
926 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000927 m_logger.log(Logger.LOG_WARNING, "Bundle start level must be greater than zero.");
Richard S. Hall930fecc2005-08-16 18:33:34 +0000928 }
929 }
930 finally
931 {
932 // Always release bundle lock.
933 releaseBundleLock((BundleImpl) bundle);
934 }
935
936 if (rethrow != null)
937 {
938 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, rethrow);
939 }
940 }
941
942 /**
943 * Returns whether a bundle is persistently started; this is an
944 * method implementation for the Start Level service.
945 * @param bundle The bundle to examine.
946 * @return <tt>true</tt> if the bundle is marked as persistently
947 * started, <tt>false</tt> otherwise.
948 * @throws java.lang.IllegalArgumentException If the specified
949 * bundle has been uninstalled.
950 **/
951 protected boolean isBundlePersistentlyStarted(Bundle bundle)
952 {
953 if (bundle.getState() == Bundle.UNINSTALLED)
954 {
955 throw new IllegalArgumentException("Bundle is uninstalled.");
956 }
957
958 return (((BundleImpl) bundle).getInfo().getPersistentState() == Bundle.ACTIVE);
959 }
960
961 //
962 // Implementation of Bundle interface methods.
963 //
964
965 /**
966 * Implementation for Bundle.getHeaders().
967 **/
968 protected Dictionary getBundleHeaders(BundleImpl bundle)
969 {
970 if (System.getSecurityManager() != null)
971 {
972 AccessController.checkPermission(m_adminPerm);
973 }
974 return new MapToDictionary(bundle.getInfo().getCurrentHeader());
975 }
976
977 /**
978 * Implementation for Bundle.getLocation().
979 **/
980 protected String getBundleLocation(BundleImpl bundle)
981 {
982 if (System.getSecurityManager() != null)
983 {
984 AccessController.checkPermission(m_adminPerm);
985 }
986 return bundle.getInfo().getLocation();
987 }
988
989 /**
990 * Implementation for Bundle.getResource().
991 **/
992 protected URL getBundleResource(BundleImpl bundle, String name)
993 {
994 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
995 {
996 throw new IllegalStateException("The bundle is uninstalled.");
997 }
998 else if (System.getSecurityManager() != null)
999 {
Richard S. Hall5d7a94a2006-02-06 12:57:30 +00001000 try
1001 {
1002 AccessController.checkPermission(
1003 new AdminPermission(bundle, AdminPermission.RESOURCE));
1004 }
1005 catch (SecurityException ex)
1006 {
1007 // Spec says to return null if there is a security exception.
1008 return null;
1009 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001010 }
Richard S. Hall001cc302006-02-03 15:03:24 +00001011 return bundle.getInfo().getCurrentModule().getResource(name);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001012 }
1013
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001014 /**
1015 * Implementation for Bundle.getEntry().
1016 **/
1017 protected URL getBundleEntry(BundleImpl bundle, String name)
1018 {
1019 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1020 {
1021 throw new IllegalStateException("The bundle is uninstalled.");
1022 }
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001023 else if (System.getSecurityManager() != null)
1024 {
Richard S. Hall5d7a94a2006-02-06 12:57:30 +00001025 try
1026 {
1027 AccessController.checkPermission(
1028 new AdminPermission(bundle, AdminPermission.RESOURCE));
1029 }
1030 catch (SecurityException ex)
1031 {
1032 // Spec says to return null if there is a security exception.
1033 return null;
1034 }
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001035 }
1036 return ((ContentLoaderImpl) bundle.getInfo().getCurrentModule()
1037 .getContentLoader()).getResourceFromContent(name);
1038 }
1039
Richard S. Hall4f09b642006-02-06 10:59:19 +00001040 /**
1041 * Implementation for Bundle.getEntryPaths().
1042 **/
1043 protected Enumeration getBundleEntryPaths(BundleImpl bundle, String path)
1044 {
1045 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1046 {
1047 throw new IllegalStateException("The bundle is uninstalled.");
1048 }
Richard S. Hall4f09b642006-02-06 10:59:19 +00001049 else if (System.getSecurityManager() != null)
1050 {
Richard S. Hall5d7a94a2006-02-06 12:57:30 +00001051 try
1052 {
1053 AccessController.checkPermission(
1054 new AdminPermission(bundle, AdminPermission.RESOURCE));
1055 }
1056 catch (SecurityException ex)
1057 {
1058 // Spec says to return null if there is a security exception.
1059 return null;
1060 }
Richard S. Hall4f09b642006-02-06 10:59:19 +00001061 }
1062 // Strip leading '/' if present.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001063 if ((path.length() > 0) && (path.charAt(0) == '/'))
Richard S. Hall4f09b642006-02-06 10:59:19 +00001064 {
1065 path = path.substring(1);
1066 }
1067 return bundle.getInfo().getCurrentModule()
1068 .getContentLoader().getContent().getEntryPaths(path);
1069 }
1070
Richard S. Hall930fecc2005-08-16 18:33:34 +00001071 protected ServiceReference[] getBundleRegisteredServices(BundleImpl bundle)
1072 {
1073 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1074 {
1075 throw new IllegalStateException("The bundle is uninstalled.");
1076 }
1077
1078 // Filter list of registered service references.
1079 ServiceReference[] refs = m_registry.getRegisteredServices(bundle);
1080 List list = new ArrayList();
1081 for (int refIdx = 0; (refs != null) && (refIdx < refs.length); refIdx++)
1082 {
1083 // Check that the current security context has permission
1084 // to get at least one of the service interfaces; the
1085 // objectClass property of the service stores its service
1086 // interfaces.
1087 boolean hasPermission = false;
1088 if (System.getSecurityManager() != null)
1089 {
1090 String[] objectClass = (String[])
1091 refs[refIdx].getProperty(Constants.OBJECTCLASS);
1092 if (objectClass == null)
1093 {
1094 return null;
1095 }
1096 for (int ifcIdx = 0;
1097 !hasPermission && (ifcIdx < objectClass.length);
1098 ifcIdx++)
1099 {
1100 try
1101 {
1102 ServicePermission perm =
1103 new ServicePermission(
1104 objectClass[ifcIdx], ServicePermission.GET);
1105 AccessController.checkPermission(perm);
1106 hasPermission = true;
1107 }
1108 catch (Exception ex)
1109 {
1110 }
1111 }
1112 }
1113 else
1114 {
1115 hasPermission = true;
1116 }
1117
1118 if (hasPermission)
1119 {
1120 list.add(refs[refIdx]);
1121 }
1122 }
1123
1124 if (list.size() > 0)
1125 {
1126 return (ServiceReference[])
1127 list.toArray(new ServiceReference[list.size()]);
1128 }
1129
1130 return null;
1131 }
1132
1133 protected ServiceReference[] getBundleServicesInUse(Bundle bundle)
1134 {
1135 // Filter list of "in use" service references.
1136 ServiceReference[] refs = m_registry.getServicesInUse(bundle);
1137 List list = new ArrayList();
1138 for (int refIdx = 0; (refs != null) && (refIdx < refs.length); refIdx++)
1139 {
1140 // Check that the current security context has permission
1141 // to get at least one of the service interfaces; the
1142 // objectClass property of the service stores its service
1143 // interfaces.
1144 boolean hasPermission = false;
1145 if (System.getSecurityManager() != null)
1146 {
1147 String[] objectClass = (String[])
1148 refs[refIdx].getProperty(Constants.OBJECTCLASS);
1149 if (objectClass == null)
1150 {
1151 return null;
1152 }
1153 for (int ifcIdx = 0;
1154 !hasPermission && (ifcIdx < objectClass.length);
1155 ifcIdx++)
1156 {
1157 try
1158 {
1159 ServicePermission perm =
1160 new ServicePermission(
1161 objectClass[ifcIdx], ServicePermission.GET);
1162 AccessController.checkPermission(perm);
1163 hasPermission = true;
1164 }
1165 catch (Exception ex)
1166 {
1167 }
1168 }
1169 }
1170 else
1171 {
1172 hasPermission = true;
1173 }
1174
1175 if (hasPermission)
1176 {
1177 list.add(refs[refIdx]);
1178 }
1179 }
1180
1181 if (list.size() > 0)
1182 {
1183 return (ServiceReference[])
1184 list.toArray(new ServiceReference[list.size()]);
1185 }
1186
1187 return null;
1188 }
1189
1190 protected boolean bundleHasPermission(BundleImpl bundle, Object obj)
1191 {
1192 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1193 {
1194 throw new IllegalStateException("The bundle is uninstalled.");
1195 }
1196
Richard S. Hall2cf44c92006-01-23 19:23:56 +00001197 if (System.getSecurityManager() != null)
Richard S. Hall65730962006-01-23 19:23:13 +00001198 {
1199 try
1200 {
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001201 return (obj instanceof java.security.Permission)
1202 ? java.security.Policy.getPolicy().getPermissions(
Richard S. Hall65730962006-01-23 19:23:13 +00001203 new java.security.CodeSource(
Richard S. Hallc762b692006-01-27 15:18:57 +00001204 new java.net.URL(bundle.getInfo().getLocation()),
1205 (java.security.cert.Certificate[]) null))
Richard S. Hall65730962006-01-23 19:23:13 +00001206 .implies((java.security.Permission) obj)
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001207 : false;
Richard S. Hall65730962006-01-23 19:23:13 +00001208 }
1209 catch (Exception ex)
1210 {
1211 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001212 Logger.LOG_WARNING,
Richard S. Hall65730962006-01-23 19:23:13 +00001213 "Exception while evaluating the permission.",
1214 ex);
1215 return false;
1216 }
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001217 }
Richard S. Hall65730962006-01-23 19:23:13 +00001218
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001219 return true;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001220 }
1221
1222 /**
Richard S. Hall74b97972005-11-30 15:51:41 +00001223 * Implementation for Bundle.loadClass().
1224 **/
1225 protected Class loadBundleClass(BundleImpl bundle, String name) throws ClassNotFoundException
1226 {
Richard S. Hallf1359482006-02-14 08:02:51 +00001227 Class clazz = bundle.getInfo().getCurrentModule().getClass(name);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001228 if (clazz == null)
Richard S. Hall74b97972005-11-30 15:51:41 +00001229 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001230 // Throw exception.
1231 ClassNotFoundException ex = new ClassNotFoundException(name);
1232
Richard S. Hall624f8012005-11-30 15:53:43 +00001233 // The spec says we must fire a framework error.
Richard S. Hall74b97972005-11-30 15:51:41 +00001234 fireFrameworkEvent(
1235 FrameworkEvent.ERROR, bundle,
1236 new BundleException(ex.getMessage()));
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001237
Richard S. Hall74b97972005-11-30 15:51:41 +00001238 throw ex;
1239 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001240 return clazz;
Richard S. Hall74b97972005-11-30 15:51:41 +00001241 }
1242
1243 /**
Richard S. Hall930fecc2005-08-16 18:33:34 +00001244 * Implementation for Bundle.start().
1245 **/
1246 protected void startBundle(BundleImpl bundle, boolean record)
1247 throws BundleException
1248 {
1249 if (System.getSecurityManager() != null)
1250 {
1251 AccessController.checkPermission(m_adminPerm);
1252 }
1253
1254 // CONCURRENCY NOTE:
1255 // Starting a bundle may actually impact many bundles, since
1256 // the bundle being started my need to be resolved, which in
1257 // turn may need to resolve other bundles. Despite this fact,
1258 // we only acquire the lock for the bundle being started, because
1259 // when resolve is called on this bundle, it will eventually
1260 // call resolve on the module loader search policy, which does
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001261 // its own locking on the module factory instance. Since the
1262 // resolve algorithm is locking the module factory instance, it
Richard S. Hall930fecc2005-08-16 18:33:34 +00001263 // is not possible for other bundles to be installed or removed,
1264 // so we don't have to worry about these possibilities.
1265 //
1266 // Further, if other bundles are started during this operation,
1267 // then either they will resolve first because they got the lock
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001268 // on the module factory or we will resolve first since we got
1269 // the lock on the module factory, so there should be no interference.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001270 // If other bundles are stopped or uninstalled, this should pose
1271 // no problems, since this does not impact their resolved state.
1272 // If a refresh occurs, then the refresh algorithm ulimately has
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001273 // to acquire the module factory instance lock too before it can
Richard S. Hall930fecc2005-08-16 18:33:34 +00001274 // completely purge old modules, so it should also complete either
1275 // before or after this bundle is started. At least that's the
1276 // theory.
1277
1278 // Acquire bundle lock.
1279 acquireBundleLock(bundle);
1280
1281 try
1282 {
1283 _startBundle(bundle, record);
1284 }
1285 finally
1286 {
1287 // Release bundle lock.
1288 releaseBundleLock(bundle);
1289 }
1290 }
1291
1292 private void _startBundle(BundleImpl bundle, boolean record)
1293 throws BundleException
1294 {
1295 // Set and save the bundle's persistent state to active
1296 // if we are supposed to record state change.
1297 if (record)
1298 {
1299 bundle.getInfo().setPersistentStateActive();
1300 }
1301
1302 // Try to start the bundle.
1303 BundleInfo info = bundle.getInfo();
1304
1305 // Ignore bundles whose persistent state is not active
1306 // or whose start level is greater than the framework's.
1307 if ((info.getPersistentState() != Bundle.ACTIVE)
1308 || (info.getStartLevel(getInitialBundleStartLevel()) > getStartLevel()))
1309 {
1310 return;
1311 }
1312
1313 switch (info.getState())
1314 {
1315 case Bundle.UNINSTALLED:
1316 throw new IllegalStateException("Cannot start an uninstalled bundle.");
1317 case Bundle.STARTING:
1318 case Bundle.STOPPING:
1319 throw new BundleException("Starting a bundle that is starting or stopping is currently not supported.");
1320 case Bundle.ACTIVE:
1321 return;
1322 case Bundle.INSTALLED:
1323 _resolveBundle(bundle);
1324 case Bundle.RESOLVED:
1325 info.setState(Bundle.STARTING);
1326 }
1327
1328 try
1329 {
1330 // Set the bundle's activator.
1331 bundle.getInfo().setActivator(createBundleActivator(bundle.getInfo()));
1332
1333 // Activate the bundle if it has an activator.
1334 if (bundle.getInfo().getActivator() != null)
1335 {
1336 if (info.getContext() == null)
1337 {
1338 info.setContext(new BundleContextImpl(this, bundle));
1339 }
1340
1341 if (System.getSecurityManager() != null)
1342 {
1343// m_startStopPrivileged.setAction(StartStopPrivileged.START_ACTION);
1344// m_startStopPrivileged.setBundle(bundle);
1345// AccessController.doPrivileged(m_startStopPrivileged);
1346 }
1347 else
1348 {
1349 info.getActivator().start(info.getContext());
1350 }
1351 }
1352
1353 info.setState(Bundle.ACTIVE);
1354
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001355 // TODO: CONCURRENCY - Reconsider firing event outside of the
1356 // bundle lock.
1357
Richard S. Hall930fecc2005-08-16 18:33:34 +00001358 fireBundleEvent(BundleEvent.STARTED, bundle);
1359 }
1360 catch (Throwable th)
1361 {
1362 // If there was an error starting the bundle,
1363 // then reset its state to RESOLVED.
1364 info.setState(Bundle.RESOLVED);
1365
Richard S. Hall187b87a2006-07-03 09:13:18 +00001366 // Clean up the bundle context, if necessary.
1367 if (info.getContext() != null)
1368 {
1369 ((BundleContextImpl) info.getContext()).invalidate();
1370 info.setContext(null);
1371 }
1372
Richard S. Hall930fecc2005-08-16 18:33:34 +00001373 // Unregister any services offered by this bundle.
1374 m_registry.unregisterServices(bundle);
1375
1376 // Release any services being used by this bundle.
1377 m_registry.ungetServices(bundle);
1378
1379 // Remove any listeners registered by this bundle.
1380 removeListeners(bundle);
1381
1382 // The spec says to expect BundleException or
1383 // SecurityException, so rethrow these exceptions.
1384 if (th instanceof BundleException)
1385 {
1386 throw (BundleException) th;
1387 }
1388 else if (th instanceof SecurityException)
1389 {
1390 throw (SecurityException) th;
1391 }
1392 // Convert a privileged action exception to the
1393 // nested exception.
1394 else if (th instanceof PrivilegedActionException)
1395 {
1396 th = ((PrivilegedActionException) th).getException();
1397 }
1398
1399 // Rethrow all other exceptions as a BundleException.
1400 throw new BundleException("Activator start error.", th);
1401 }
1402 }
1403
1404 protected void _resolveBundle(BundleImpl bundle)
1405 throws BundleException
1406 {
1407 // If a security manager is installed, then check for permission
1408 // to import the necessary packages.
1409 if (System.getSecurityManager() != null)
1410 {
1411 URL url = null;
1412 try
1413 {
1414 url = new URL(bundle.getInfo().getLocation());
1415 }
1416 catch (MalformedURLException ex)
1417 {
1418 throw new BundleException("Cannot resolve, bad URL "
1419 + bundle.getInfo().getLocation());
1420 }
1421
1422// try
1423// {
1424// AccessController.doPrivileged(new CheckImportsPrivileged(url, bundle));
1425// }
1426// catch (PrivilegedActionException ex)
1427// {
1428// Exception thrown = ((PrivilegedActionException) ex).getException();
1429// if (thrown instanceof AccessControlException)
1430// {
1431// throw (AccessControlException) thrown;
1432// }
1433// else
1434// {
1435// throw new BundleException("Problem resolving: " + ex);
1436// }
1437// }
1438 }
1439
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001440 IModule module = bundle.getInfo().getCurrentModule();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001441 try
1442 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001443 m_policyCore.resolve(module);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001444 }
1445 catch (ResolveException ex)
1446 {
1447 if (ex.getModule() != null)
1448 {
1449 throw new BundleException(
1450 "Unresolved package in bundle "
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001451 + Util.getBundleIdFromModuleId(ex.getModule().getId())
Richard S. Hall930fecc2005-08-16 18:33:34 +00001452 + ": " + ex.getPackage());
1453 }
1454 else
1455 {
1456 throw new BundleException(ex.getMessage());
1457 }
1458 }
1459
1460 bundle.getInfo().setState(Bundle.RESOLVED);
1461 }
1462
1463 protected void updateBundle(BundleImpl bundle, InputStream is)
1464 throws BundleException
1465 {
1466 if (System.getSecurityManager() != null)
1467 {
1468 AccessController.checkPermission(m_adminPerm);
1469 }
1470
1471 // Acquire bundle lock.
1472 acquireBundleLock(bundle);
1473
1474 try
1475 {
1476 _updateBundle(bundle, is);
1477 }
1478 finally
1479 {
1480 // Release bundle lock.
1481 releaseBundleLock(bundle);
1482 }
1483 }
1484
1485 protected void _updateBundle(BundleImpl bundle, InputStream is)
1486 throws BundleException
1487 {
1488 // We guarantee to close the input stream, so put it in a
1489 // finally clause.
1490
1491 try
1492 {
1493 // Variable to indicate whether bundle is active or not.
1494 Exception rethrow = null;
1495
1496 // Cannot update an uninstalled bundle.
1497 BundleInfo info = bundle.getInfo();
1498 if (info.getState() == Bundle.UNINSTALLED)
1499 {
1500 throw new IllegalStateException("The bundle is uninstalled.");
1501 }
1502
1503 // First get the update-URL from our header.
1504 String updateLocation = (String)
1505 info.getCurrentHeader().get(Constants.BUNDLE_UPDATELOCATION);
1506
1507 // If no update location specified, use original location.
1508 if (updateLocation == null)
1509 {
1510 updateLocation = info.getLocation();
1511 }
1512
1513 // Stop the bundle, but do not change the persistent state.
1514 stopBundle(bundle, false);
1515
1516 try
1517 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001518 // Get the bundle's archive.
Richard S. Hall04bdbb12006-03-15 14:26:15 +00001519 BundleArchive archive = m_cache.getArchive(info.getBundleId());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001520 // Update the bundle; this operation will increase
1521 // the revision count for the bundle.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001522 archive.revise(updateLocation, is);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001523 // Create a module for the new revision; the revision is
1524 // base zero, so subtract one from the revision count to
1525 // get the revision of the new update.
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001526 try
1527 {
1528 IModule module = createModule(
1529 info.getBundleId(),
1530 archive.getRevisionCount() - 1,
1531 info.getCurrentHeader());
1532 // Add module to bundle info.
1533 info.addModule(module);
1534 }
1535 catch (Exception ex)
1536 {
1537 rethrow = ex;
1538
1539 try
1540 {
1541 archive.undoRevise();
1542 }
1543 catch (Exception busted)
1544 {
1545 m_logger.log(Logger.LOG_ERROR, "Unable to rollback.", busted);
1546 }
1547
1548 m_logger.log(Logger.LOG_ERROR, "Unable to update the bundle.", ex);
1549 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001550 }
1551 catch (Exception ex)
1552 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001553 m_logger.log(Logger.LOG_ERROR, "Unable to update the bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001554 rethrow = ex;
1555 }
1556
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001557 // Set new state, mark as needing a refresh, and fire updated event
1558 // if successful.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001559 if (rethrow == null)
1560 {
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001561 info.setState(Bundle.INSTALLED);
1562 info.setLastModified(System.currentTimeMillis());
1563
Richard S. Hall60c26d42006-07-19 10:35:04 +00001564 // Mark previous the bundle's old module for removal since
1565 // it can no longer be used to resolve other modules per the spec.
1566 IModule module = info.getModules()[info.getModules().length - 2];
1567 m_policyCore.setRemovalPending(module, true);
1568
Richard S. Hall930fecc2005-08-16 18:33:34 +00001569 fireBundleEvent(BundleEvent.UPDATED, bundle);
1570 }
1571
1572 // Restart bundle, but do not change the persistent state.
1573 // This will not start the bundle if it was not previously
1574 // active.
1575 startBundle(bundle, false);
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001576
Richard S. Hall930fecc2005-08-16 18:33:34 +00001577 // If update failed, rethrow exception.
1578 if (rethrow != null)
1579 {
1580 throw new BundleException("Update failed.", rethrow);
1581 }
1582 }
1583 finally
1584 {
1585 try
1586 {
1587 if (is != null) is.close();
1588 }
1589 catch (IOException ex)
1590 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001591 m_logger.log(Logger.LOG_ERROR, "Unable to close input stream.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001592 }
1593 }
1594 }
1595
1596 protected void stopBundle(BundleImpl bundle, boolean record)
1597 throws BundleException
1598 {
1599 if (System.getSecurityManager() != null)
1600 {
1601 AccessController.checkPermission(m_adminPerm);
1602 }
1603
1604 // Acquire bundle lock.
1605 acquireBundleLock(bundle);
1606
1607 try
1608 {
1609 _stopBundle(bundle, record);
1610 }
1611 finally
1612 {
1613 // Always release bundle lock.
1614 releaseBundleLock(bundle);
1615 }
1616 }
1617
1618 private void _stopBundle(BundleImpl bundle, boolean record)
1619 throws BundleException
1620 {
1621 Throwable rethrow = null;
1622
1623 // Set the bundle's persistent state to inactive if necessary.
1624 if (record)
1625 {
1626 bundle.getInfo().setPersistentStateInactive();
1627 }
1628
1629 BundleInfo info = bundle.getInfo();
1630
1631 switch (info.getState())
1632 {
1633 case Bundle.UNINSTALLED:
1634 throw new IllegalStateException("Cannot stop an uninstalled bundle.");
1635 case Bundle.STARTING:
1636 case Bundle.STOPPING:
1637 throw new BundleException("Stopping a bundle that is starting or stopping is currently not supported.");
1638 case Bundle.INSTALLED:
1639 case Bundle.RESOLVED:
1640 return;
1641 case Bundle.ACTIVE:
1642 // Set bundle state..
1643 info.setState(Bundle.STOPPING);
1644 }
1645
1646 try
1647 {
1648 if (bundle.getInfo().getActivator() != null)
1649 {
1650 if (System.getSecurityManager() != null)
1651 {
1652// m_startStopPrivileged.setAction(StartStopPrivileged.STOP_ACTION);
1653// m_startStopPrivileged.setBundle(bundle);
1654// AccessController.doPrivileged(m_startStopPrivileged);
1655 }
1656 else
1657 {
1658 info.getActivator().stop(info.getContext());
1659 }
1660 }
1661
1662 // Try to save the activator in the cache.
1663 // NOTE: This is non-standard OSGi behavior and only
1664 // occurs if strictness is disabled.
1665 String strict = m_config.get(FelixConstants.STRICT_OSGI_PROP);
1666 boolean isStrict = (strict == null) ? true : strict.equals("true");
1667 if (!isStrict)
1668 {
1669 try
1670 {
1671 m_cache.getArchive(info.getBundleId())
1672 .setActivator(info.getActivator());
1673 }
1674 catch (Exception ex)
1675 {
1676 // Problem saving activator, so ignore it.
1677 // TODO: Perhaps we should handle this some other way?
1678 }
1679 }
1680 }
1681 catch (Throwable th)
1682 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001683 m_logger.log(Logger.LOG_ERROR, "Error stopping bundle.", th);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001684 rethrow = th;
1685 }
1686
Richard S. Hall187b87a2006-07-03 09:13:18 +00001687 // Clean up the bundle context, if necessary.
1688 if (info.getContext() != null)
1689 {
1690 ((BundleContextImpl) info.getContext()).invalidate();
1691 info.setContext(null);
1692 }
1693
Richard S. Hall930fecc2005-08-16 18:33:34 +00001694 // Unregister any services offered by this bundle.
1695 m_registry.unregisterServices(bundle);
1696
1697 // Release any services being used by this bundle.
1698 m_registry.ungetServices(bundle);
1699
1700 // The spec says that we must remove all event
1701 // listeners for a bundle when it is stopped.
1702 removeListeners(bundle);
1703
1704 info.setState(Bundle.RESOLVED);
1705 fireBundleEvent(BundleEvent.STOPPED, bundle);
1706
1707 // Throw activator error if there was one.
1708 if (rethrow != null)
1709 {
1710 // The spec says to expect BundleException or
1711 // SecurityException, so rethrow these exceptions.
1712 if (rethrow instanceof BundleException)
1713 {
1714 throw (BundleException) rethrow;
1715 }
1716 else if (rethrow instanceof SecurityException)
1717 {
1718 throw (SecurityException) rethrow;
1719 }
1720 else if (rethrow instanceof PrivilegedActionException)
1721 {
1722 rethrow = ((PrivilegedActionException) rethrow).getException();
1723 }
1724
1725 // Rethrow all other exceptions as a BundleException.
1726 throw new BundleException("Activator stop error.", rethrow);
1727 }
1728 }
1729
1730 protected void uninstallBundle(BundleImpl bundle) throws BundleException
1731 {
1732 if (System.getSecurityManager() != null)
1733 {
1734 AccessController.checkPermission(m_adminPerm);
1735 }
1736
1737 // Acquire bundle lock.
1738 acquireBundleLock(bundle);
1739
1740 try
1741 {
1742 _uninstallBundle(bundle);
1743 }
1744 finally
1745 {
1746 // Always release bundle lock.
1747 releaseBundleLock(bundle);
1748 }
1749 }
1750
1751 private void _uninstallBundle(BundleImpl bundle) throws BundleException
1752 {
1753 if (System.getSecurityManager() != null)
1754 {
1755 AccessController.checkPermission(m_adminPerm);
1756 }
1757
Richard S. Hall930fecc2005-08-16 18:33:34 +00001758 BundleInfo info = bundle.getInfo();
1759 if (info.getState() == Bundle.UNINSTALLED)
1760 {
1761 throw new IllegalStateException("The bundle is uninstalled.");
1762 }
1763
1764 // The spec says that uninstall should always succeed, so
1765 // catch an exception here if stop() doesn't succeed and
1766 // rethrow it at the end.
1767 try
1768 {
1769 stopBundle(bundle, true);
1770 }
1771 catch (BundleException ex)
1772 {
Richard S. Hall447c52f2006-07-04 09:25:07 +00001773 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001774 }
1775
1776 // Remove the bundle from the installed map.
1777 BundleImpl target = null;
1778 synchronized (m_installedBundleLock_Priority2)
1779 {
1780 target = (BundleImpl) m_installedBundleMap.remove(info.getLocation());
1781 }
1782
1783 // Finally, put the uninstalled bundle into the
1784 // uninstalled list for subsequent refreshing.
1785 if (target != null)
1786 {
1787 // Set the bundle's persistent state to uninstalled.
1788 target.getInfo().setPersistentStateUninstalled();
1789
Richard S. Hall60c26d42006-07-19 10:35:04 +00001790 // Mark current module for removal since it can no longer
1791 // be used to resolve other modules per the spec.
1792 m_policyCore.setRemovalPending(target.getInfo().getCurrentModule(), true);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001793
1794 // Put bundle in uninstalled bundle array.
1795 rememberUninstalledBundle(bundle);
1796 }
1797 else
1798 {
1799 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001800 Logger.LOG_ERROR, "Unable to remove bundle from installed map!");
Richard S. Hall930fecc2005-08-16 18:33:34 +00001801 }
1802
1803 // Set state to uninstalled.
1804 info.setState(Bundle.UNINSTALLED);
Richard S. Hall69d84792006-01-13 13:55:13 +00001805 info.setLastModified(System.currentTimeMillis());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001806
1807 // Fire bundle event.
1808 fireBundleEvent(BundleEvent.UNINSTALLED, bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001809 }
1810
1811 //
1812 // Implementation of BundleContext interface methods.
1813 //
1814
1815 /**
1816 * Implementation for BundleContext.getProperty(). Returns
1817 * environment property associated with the framework.
1818 *
1819 * @param key The name of the property to retrieve.
1820 * @return The value of the specified property or null.
1821 **/
1822 protected String getProperty(String key)
1823 {
1824 // First, check the config properties.
Richard S. Hallea415752005-12-05 19:30:28 +00001825 String val = (String) m_config.get(key);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001826 // If not found, then try the system properties.
1827 return (val == null) ? System.getProperty(key) : val;
1828 }
1829
1830 protected Bundle installBundle(String location, InputStream is)
1831 throws BundleException
1832 {
1833 return installBundle(-1, location, is);
1834 }
1835
1836 private Bundle installBundle(long id, String location, InputStream is)
1837 throws BundleException
1838 {
1839 if (System.getSecurityManager() != null)
1840 {
1841 AccessController.checkPermission(m_adminPerm);
1842 }
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001843
Richard S. Hall930fecc2005-08-16 18:33:34 +00001844 BundleImpl bundle = null;
1845
1846 // Acquire an install lock.
1847 acquireInstallLock(location);
1848
1849 try
1850 {
1851 // Check to see if the framework is still running;
1852 if ((getStatus() == Felix.STOPPING_STATUS) ||
1853 (getStatus() == Felix.INITIAL_STATUS))
1854 {
1855 throw new BundleException("The framework has been shutdown.");
1856 }
1857
1858 // If bundle location is already installed, then
1859 // return it as required by the OSGi specification.
1860 bundle = (BundleImpl) getBundle(location);
1861 if (bundle != null)
1862 {
1863 return bundle;
1864 }
1865
1866 // Determine if this is a new or existing bundle.
1867 boolean isNew = (id < 0);
1868
1869 // If the bundle is new we must cache its JAR file.
1870 if (isNew)
1871 {
1872 // First generate an identifier for it.
1873 id = getNextId();
1874
1875 try
1876 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001877 // Add the bundle to the cache.
Richard S. Hall9a3e9852006-03-04 03:44:05 +00001878 m_cache.create(id, location, is);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001879 }
1880 catch (Exception ex)
1881 {
1882 throw new BundleException(
1883 "Unable to cache bundle: " + location, ex);
1884 }
1885 finally
1886 {
1887 try
1888 {
1889 if (is != null) is.close();
1890 }
1891 catch (IOException ex)
1892 {
1893 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001894 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001895 "Unable to close input stream.", ex);
1896 }
1897 }
1898 }
1899 else
1900 {
1901 // If the bundle we are installing is not new,
1902 // then try to purge old revisions before installing
1903 // it; this is done just in case a "refresh"
1904 // didn't occur last session...this would only be
1905 // due to an error or system crash.
1906 try
1907 {
1908 if (m_cache.getArchive(id).getRevisionCount() > 1)
1909 {
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001910 m_cache.getArchive(id).purge();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001911 }
1912 }
1913 catch (Exception ex)
1914 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001915 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001916 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001917 "Could not purge bundle.", ex);
1918 }
1919 }
1920
1921 try
1922 {
Richard S. Hall04bdbb12006-03-15 14:26:15 +00001923 BundleArchive archive = m_cache.getArchive(id);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001924 bundle = new BundleImpl(this, createBundleInfo(archive));
1925 }
1926 catch (Exception ex)
1927 {
1928 // If the bundle is new, then remove it from the cache.
1929 // TODO: Perhaps it should be removed if it is not new too.
1930 if (isNew)
1931 {
1932 try
1933 {
1934 m_cache.remove(m_cache.getArchive(id));
1935 }
1936 catch (Exception ex1)
1937 {
1938 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001939 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001940 "Could not remove from cache.", ex1);
1941 }
1942 }
1943 throw new BundleException("Could not create bundle object.", ex);
1944 }
1945
1946 // If the bundle is new, then set its start level; existing
1947 // bundles already have their start level set.
1948 if (isNew)
1949 {
1950 // This will persistently set the bundle's start level.
1951 bundle.getInfo().setStartLevel(getInitialBundleStartLevel());
Richard S. Hall69d84792006-01-13 13:55:13 +00001952 bundle.getInfo().setLastModified(System.currentTimeMillis());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001953 }
1954
1955 synchronized (m_installedBundleLock_Priority2)
1956 {
1957 m_installedBundleMap.put(location, bundle);
1958 }
1959 }
1960 finally
1961 {
1962 // Always release install lock.
1963 releaseInstallLock(location);
1964
1965 // Always try to close the input stream.
1966 try
1967 {
1968 if (is != null) is.close();
1969 }
1970 catch (IOException ex)
1971 {
1972 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001973 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00001974 "Unable to close input stream.", ex);
1975 // Not much else we can do.
1976 }
1977 }
1978
1979 // Fire bundle event.
1980 fireBundleEvent(BundleEvent.INSTALLED, bundle);
1981
1982 // Return new bundle.
1983 return bundle;
1984 }
1985
1986 /**
1987 * Retrieves a bundle from its location.
1988 *
1989 * @param location The location of the bundle to retrieve.
1990 * @return The bundle associated with the location or null if there
1991 * is no bundle associated with the location.
1992 **/
1993 protected Bundle getBundle(String location)
1994 {
1995 synchronized (m_installedBundleLock_Priority2)
1996 {
1997 return (Bundle) m_installedBundleMap.get(location);
1998 }
1999 }
2000
2001 /**
2002 * Implementation for BundleContext.getBundle(). Retrieves a
2003 * bundle from its identifier.
2004 *
2005 * @param id The identifier of the bundle to retrieve.
2006 * @return The bundle associated with the identifier or null if there
2007 * is no bundle associated with the identifier.
2008 **/
2009 protected Bundle getBundle(long id)
2010 {
2011 synchronized (m_installedBundleLock_Priority2)
2012 {
2013 BundleImpl bundle = null;
2014
2015 for (Iterator i = m_installedBundleMap.values().iterator(); i.hasNext(); )
2016 {
2017 bundle = (BundleImpl) i.next();
2018 if (bundle.getInfo().getBundleId() == id)
2019 {
2020 return bundle;
2021 }
2022 }
2023 }
2024
Richard S. Halla6443462006-06-29 15:16:05 +00002025 synchronized (m_uninstalledBundlesLock_Priority3)
2026 {
2027 for (int i = 0; i < m_uninstalledBundles.length; i++)
2028 {
2029 if (m_uninstalledBundles[i].getInfo().getBundleId() == id)
2030 {
2031 return m_uninstalledBundles[i];
2032 }
2033 }
2034 }
2035
Richard S. Hall930fecc2005-08-16 18:33:34 +00002036 return null;
2037 }
2038
2039 // Private member for method below.
2040 private Comparator m_comparator = null;
2041
2042 /**
2043 * Implementation for BundleContext.getBundles(). Retrieves
2044 * all installed bundles.
2045 *
2046 * @return An array containing all installed bundles or null if
2047 * there are no installed bundles.
2048 **/
2049 protected Bundle[] getBundles()
2050 {
2051 if (m_comparator == null)
2052 {
2053 m_comparator = new Comparator() {
2054 public int compare(Object o1, Object o2)
2055 {
2056 Bundle b1 = (Bundle) o1;
2057 Bundle b2 = (Bundle) o2;
2058 if (b1.getBundleId() > b2.getBundleId())
2059 return 1;
2060 else if (b1.getBundleId() < b2.getBundleId())
2061 return -1;
2062 return 0;
2063 }
2064 };
2065 }
2066
2067 Bundle[] bundles = null;
2068
2069 synchronized (m_installedBundleLock_Priority2)
2070 {
2071 if (m_installedBundleMap.size() == 0)
2072 {
2073 return null;
2074 }
2075
2076 bundles = new Bundle[m_installedBundleMap.size()];
2077 int counter = 0;
2078 for (Iterator i = m_installedBundleMap.values().iterator(); i.hasNext(); )
2079 {
2080 bundles[counter++] = (Bundle) i.next();
2081 }
2082 }
2083
2084 Arrays.sort(bundles, m_comparator);
2085
2086 return bundles;
2087 }
2088
2089 protected void addBundleListener(Bundle bundle, BundleListener l)
2090 {
2091 // The spec says do nothing if the listener is
2092 // already registered.
2093 BundleListenerWrapper old = (BundleListenerWrapper)
2094 m_dispatchQueue.getListener(BundleListener.class, l);
2095 if (old == null)
2096 {
2097 l = new BundleListenerWrapper(bundle, l);
2098 m_dispatchQueue.addListener(BundleListener.class, l);
2099 }
2100 }
2101
2102 protected void removeBundleListener(BundleListener l)
2103 {
2104 m_dispatchQueue.removeListener(BundleListener.class, l);
2105 }
2106
2107 /**
2108 * Implementation for BundleContext.addServiceListener().
2109 * Adds service listener to the listener list so that is
2110 * can listen for <code>ServiceEvent</code>s.
2111 *
2112 * @param bundle The bundle that registered the listener.
2113 * @param l The service listener to add to the listener list.
2114 * @param f The filter for the listener; may be null.
2115 **/
2116 protected void addServiceListener(Bundle bundle, ServiceListener l, String f)
2117 throws InvalidSyntaxException
2118 {
2119 // The spec says if the listener is already registered,
2120 // then replace filter.
2121 ServiceListenerWrapper old = (ServiceListenerWrapper)
2122 m_dispatchQueue.getListener(ServiceListener.class, l);
2123 if (old != null)
2124 {
2125 old.setFilter((f == null) ? null : new FilterImpl(m_logger, f));
2126 }
2127 else
2128 {
2129 l = new ServiceListenerWrapper(
2130 bundle, l, (f == null) ? null : new FilterImpl(m_logger, f));
2131 m_dispatchQueue.addListener(ServiceListener.class, l);
2132 }
2133 }
2134
2135 /**
2136 * Implementation for BundleContext.removeServiceListener().
2137 * Removes service listeners from the listener list.
2138 *
2139 * @param l The service listener to remove from the listener list.
2140 **/
2141 protected void removeServiceListener(ServiceListener l)
2142 {
2143 m_dispatchQueue.removeListener(ServiceListener.class, l);
2144 }
2145
2146 protected void addFrameworkListener(Bundle bundle, FrameworkListener l)
2147 {
2148 // The spec says do nothing if the listener is
2149 // already registered.
2150 FrameworkListenerWrapper old = (FrameworkListenerWrapper)
2151 m_dispatchQueue.getListener(FrameworkListener.class, l);
2152 if (old == null)
2153 {
2154 l = new FrameworkListenerWrapper(bundle, l);
2155 m_dispatchQueue.addListener(FrameworkListener.class, l);
2156 }
2157 }
2158
2159 protected void removeFrameworkListener(FrameworkListener l)
2160 {
2161 m_dispatchQueue.removeListener(FrameworkListener.class, l);
2162 }
2163
2164 /**
2165 * Remove all of the specified bundle's event listeners from
2166 * the framework.
2167 * @param bundle The bundle whose listeners are to be removed.
2168 **/
2169 private void removeListeners(Bundle bundle)
2170 {
2171 if (bundle == null)
2172 {
2173 return;
2174 }
2175
2176 // Remove all listeners associated with the supplied bundle;
2177 // it is only possible to know the bundle associated with a
2178 // listener if the listener was wrapper by a ListenerWrapper,
2179 // so look for those.
2180 Object[] listeners = m_dispatchQueue.getListeners();
2181 for (int i = listeners.length - 2; i >= 0; i -= 2)
2182 {
2183 // Check for listener wrappers and then compare the bundle.
2184 if (listeners[i + 1] instanceof ListenerWrapper)
2185 {
2186 ListenerWrapper lw = (ListenerWrapper) listeners[i + 1];
2187 if ((lw.getBundle() != null) && (lw.getBundle().equals(bundle)))
2188 {
2189 m_dispatchQueue.removeListener(
2190 (Class) listeners[i], (EventListener) listeners[i+1]);
2191 }
2192 }
2193 }
2194 }
2195
2196 /**
2197 * Implementation for BundleContext.registerService(). Registers
2198 * a service for the specified bundle bundle.
2199 *
2200 * @param classNames A string array containing the names of the classes
2201 * under which the new service is available.
2202 * @param svcObj The service object or <code>ServiceFactory</code>.
2203 * @param dict A dictionary of properties that further describe the
2204 * service or null.
2205 * @return A <code>ServiceRegistration</code> object or null.
2206 **/
2207 protected ServiceRegistration registerService(
2208 BundleImpl bundle, String[] classNames, Object svcObj, Dictionary dict)
2209 {
2210 if (classNames == null)
2211 {
2212 throw new NullPointerException("Service class names cannot be null.");
2213 }
2214 else if (svcObj == null)
2215 {
2216 throw new IllegalArgumentException("Service object cannot be null.");
2217 }
2218
2219 // Check for permission to register all passed in interface names.
2220 if (System.getSecurityManager() != null)
2221 {
2222 for (int i = 0; i < classNames.length; i++)
2223 {
2224 ServicePermission perm = new ServicePermission(
2225 classNames[i], ServicePermission.REGISTER);
2226 AccessController.checkPermission(perm);
2227 }
2228 }
2229
2230 // Acquire bundle lock.
Richard S. Hall3c26cc02006-02-17 13:51:21 +00002231 acquireBundleLock(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002232
2233 ServiceRegistration reg = null;
2234
2235 try
2236 {
2237 BundleInfo info = bundle.getInfo();
2238
2239 // Can only register services if starting or active.
2240 if ((info.getState() & (Bundle.STARTING | Bundle.ACTIVE)) == 0)
2241 {
2242 throw new IllegalStateException(
2243 "Can only register services while bundle is active or activating.");
2244 }
2245
2246 // Check to make sure that the service object is
2247 // an instance of all service classes; ignore if
2248 // service object is a service factory.
2249 if (!(svcObj instanceof ServiceFactory))
2250 {
2251 for (int i = 0; i < classNames.length; i++)
2252 {
Richard S. Hallbc549622006-07-13 13:33:22 +00002253 Class clazz = Util.loadClassUsingClass(svcObj.getClass(), classNames[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002254 if (clazz == null)
2255 {
2256 throw new IllegalArgumentException(
2257 "Cannot cast service: " + classNames[i]);
2258 }
2259 else if (!clazz.isAssignableFrom(svcObj.getClass()))
2260 {
2261 throw new IllegalArgumentException(
2262 "Service object is not an instance of \""
2263 + classNames[i] + "\".");
2264 }
2265 }
2266 }
2267
2268 reg = m_registry.registerService(bundle, classNames, svcObj, dict);
2269 }
2270 finally
2271 {
2272 // Always release bundle lock.
2273 releaseBundleLock(bundle);
2274 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +00002275
2276 // TODO: CONCURRENCY - Reconsider firing event here, outside of the
2277 // bundle lock.
2278
Richard S. Hall930fecc2005-08-16 18:33:34 +00002279 // NOTE: The service registered event is fired from the service
2280 // registry to the framework, where it is then redistributed to
2281 // interested service event listeners.
2282
2283 return reg;
2284 }
2285
Richard S. Hall930fecc2005-08-16 18:33:34 +00002286 protected ServiceReference[] getServiceReferences(
2287 BundleImpl bundle, String className, String expr)
2288 throws InvalidSyntaxException
2289 {
2290 // Define filter if expression is not null.
2291 Filter filter = null;
2292 if (expr != null)
2293 {
2294 filter = new FilterImpl(m_logger, expr);
2295 }
2296
2297 // Ask the service registry for all matching service references.
2298 List refList = m_registry.getServiceReferences(className, filter);
2299
2300 // The returned reference list must be filtered for two cases:
2301 // 1) The requesting bundle may not be wired to the same class
2302 // as the providing bundle (i.e, different versions), so filter
2303 // any services for which the requesting bundle might get a
2304 // class cast exception.
2305 // 2) Security is enabled and the requesting bundle does not have
2306 // permission access the service.
2307 for (int refIdx = 0; (refList != null) && (refIdx < refList.size()); refIdx++)
2308 {
2309 // Get the current service reference.
2310 ServiceReference ref = (ServiceReference) refList.get(refIdx);
2311
2312 // Get the service's objectClass property.
2313 String[] objectClass = (String[]) ref.getProperty(FelixConstants.OBJECTCLASS);
2314
2315 // Boolean flag.
2316 boolean allow = false;
2317
2318 // Filter the service reference if the requesting bundle
2319 // does not have permission.
2320 if (System.getSecurityManager() != null)
2321 {
2322 for (int classIdx = 0;
2323 !allow && (classIdx < objectClass.length);
2324 classIdx++)
2325 {
2326 try
2327 {
2328 ServicePermission perm = new ServicePermission(
2329 objectClass[classIdx], ServicePermission.GET);
2330 AccessController.checkPermission(perm);
2331 // The bundle only needs permission for one
2332 // of the service interfaces, so break out
2333 // of the loop when permission is granted.
2334 allow = true;
2335 }
2336 catch (Exception ex)
2337 {
2338 // We do not throw this exception since the bundle
2339 // is not supposed to know about the service at all
2340 // if it does not have permission.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002341 m_logger.log(Logger.LOG_ERROR, ex.getMessage());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002342 }
2343 }
2344
2345 if (!allow)
2346 {
2347 refList.remove(refIdx);
2348 refIdx--;
2349 continue;
2350 }
2351 }
2352
2353 // Now check for castability.
2354 if (!isServiceAssignable(bundle, ref))
2355 {
2356 refList.remove(refIdx);
2357 refIdx--;
2358 }
2359 }
2360
2361 if (refList.size() > 0)
2362 {
2363 return (ServiceReference[]) refList.toArray(new ServiceReference[refList.size()]);
2364 }
2365
2366 return null;
2367 }
2368
2369 /**
2370 * This method determines if the requesting bundle is able to cast
2371 * the specified service reference based on class visibility rules
2372 * of the underlying modules.
2373 * @param requester The bundle requesting the service.
2374 * @param ref The service in question.
2375 * @return <tt>true</tt> if the requesting bundle is able to case
2376 * the service object to a known type.
2377 **/
2378 protected boolean isServiceAssignable(BundleImpl requester, ServiceReference ref)
2379 {
2380 // Boolean flag.
2381 boolean allow = true;
2382 // Get the service's objectClass property.
2383 String[] objectClass = (String[]) ref.getProperty(FelixConstants.OBJECTCLASS);
2384
2385 // The the service reference is not assignable when the requesting
2386 // bundle is wired to a different version of the service object.
2387 // NOTE: We are pessimistic here, if any class in the service's
2388 // objectClass is not usable by the requesting bundle, then we
2389 // disallow the service reference.
2390 for (int classIdx = 0; (allow) && (classIdx < objectClass.length); classIdx++)
2391 {
2392 if (!ref.isAssignableTo(requester, objectClass[classIdx]))
2393 {
2394 allow = false;
2395 }
2396 }
2397 return allow;
2398 }
2399
2400 protected Object getService(Bundle bundle, ServiceReference ref)
2401 {
2402 // Check that the bundle has permission to get at least
2403 // one of the service interfaces; the objectClass property
2404 // of the service stores its service interfaces.
2405 String[] objectClass = (String[])
2406 ref.getProperty(Constants.OBJECTCLASS);
2407 if (objectClass == null)
2408 {
2409 return null;
2410 }
2411
2412 boolean hasPermission = false;
2413 if (System.getSecurityManager() != null)
2414 {
2415 for (int i = 0;
2416 !hasPermission && (i < objectClass.length);
2417 i++)
2418 {
2419 try
2420 {
2421 ServicePermission perm =
2422 new ServicePermission(
2423 objectClass[i], ServicePermission.GET);
2424 AccessController.checkPermission(perm);
2425 hasPermission = true;
2426 }
2427 catch (Exception ex)
2428 {
2429 }
2430 }
2431 }
2432 else
2433 {
2434 hasPermission = true;
2435 }
2436
2437 // If the bundle does not permission to access the service,
2438 // then return null.
2439 if (!hasPermission)
2440 {
2441 return null;
2442 }
2443
2444 return m_registry.getService(bundle, ref);
2445 }
2446
2447 protected boolean ungetService(Bundle bundle, ServiceReference ref)
2448 {
2449 return m_registry.ungetService(bundle, ref);
2450 }
2451
2452 protected File getDataFile(BundleImpl bundle, String s)
2453 {
2454 // The spec says to throw an error if the bundle
2455 // is stopped, which I assume means not active,
2456 // starting, or stopping.
2457 if ((bundle.getInfo().getState() != Bundle.ACTIVE) &&
2458 (bundle.getInfo().getState() != Bundle.STARTING) &&
2459 (bundle.getInfo().getState() != Bundle.STOPPING))
2460 {
2461 throw new IllegalStateException("Only active bundles can create files.");
2462 }
2463 try
2464 {
2465 return m_cache.getArchive(
2466 bundle.getInfo().getBundleId()).getDataFile(s);
2467 }
2468 catch (Exception ex)
2469 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002470 m_logger.log(Logger.LOG_ERROR, ex.getMessage());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002471 return null;
2472 }
2473 }
2474
2475 //
2476 // PackageAdmin related methods.
2477 //
2478
2479 /**
Richard S. Hallc87d41a2006-07-03 07:57:28 +00002480 * This method returns the bundle associated with the specified class if
2481 * the class was loaded from a bundle from this framework instance. If the
2482 * class was not loaded from a bundle or was loaded by a bundle in another
2483 * framework instance, then <tt>null</tt> is returned.
2484 *
2485 * @param clazz the class for which to find its associated bundle.
2486 * @return the bundle associated with the specified class or <tt>null</tt>
2487 * if the class was not loaded by a bundle or its associated
2488 * bundle belongs to a different framework instance.
2489 **/
2490 protected Bundle getBundle(Class clazz)
2491 {
2492 if (clazz.getClassLoader() instanceof ContentClassLoader)
2493 {
2494 IContentLoader contentLoader =
2495 ((ContentClassLoader) clazz.getClassLoader()).getContentLoader();
2496 IModule[] modules = m_factory.getModules();
2497 for (int i = 0; i < modules.length; i++)
2498 {
2499 if (modules[i].getContentLoader() == contentLoader)
2500 {
2501 long id = Util.getBundleIdFromModuleId(modules[i].getId());
2502 return getBundle(id);
2503 }
2504 }
2505 }
2506 return null;
2507 }
2508
2509 /**
Richard S. Hall1bdc3722006-07-03 09:52:07 +00002510 * Returns the exported packages associated with the specified
Richard S. Hallafc52d42006-02-09 13:04:32 +00002511 * package name. This is used by the PackageAdmin service
2512 * implementation.
2513 *
2514 * @param name The name of the exported package to find.
2515 * @return The exported package or null if no matching package was found.
2516 **/
2517 protected ExportedPackage[] getExportedPackages(String name)
2518 {
2519 // First, get all exporters of the package.
2520 ExportedPackage[] pkgs = null;
2521 IModule[] exporters = m_policyCore.getInUseExporters(new R4Import(name, null, null));
Richard S. Hall930fecc2005-08-16 18:33:34 +00002522 if (exporters != null)
2523 {
Richard S. Hall88e0ae62006-02-09 13:22:21 +00002524 pkgs = new ExportedPackage[exporters.length];
Richard S. Hallafc52d42006-02-09 13:04:32 +00002525 for (int pkgIdx = 0; pkgIdx < pkgs.length; pkgIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002526 {
Richard S. Hallafc52d42006-02-09 13:04:32 +00002527 // Get the bundle associated with the current exporting module.
2528 BundleImpl bundle = (BundleImpl) getBundle(
2529 Util.getBundleIdFromModuleId(exporters[pkgIdx].getId()));
2530
2531 // We need to find the version of the exported package, but this
2532 // is tricky since there may be multiple versions of the package
2533 // offered by a given bundle, since multiple revisions of the
2534 // bundle JAR file may exist if the bundle was updated without
2535 // refreshing the framework. In this case, each revision of the
2536 // bundle JAR file is represented as a module in the BundleInfo
2537 // module array, which is ordered from oldest to newest. We assume
2538 // that the first module found to be exporting the package is the
2539 // provider of the package, which makes sense since it must have
2540 // been resolved first.
2541 IModule[] modules = bundle.getInfo().getModules();
2542 for (int modIdx = 0; modIdx < modules.length; modIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002543 {
Richard S. Hallafc52d42006-02-09 13:04:32 +00002544 R4Export export = Util.getExportPackage(modules[modIdx], name);
2545 if (export != null)
2546 {
2547 pkgs[pkgIdx] =
2548 new ExportedPackageImpl(
Richard S. Hall60c26d42006-07-19 10:35:04 +00002549 this, bundle, modules[modIdx], export);
Richard S. Hallafc52d42006-02-09 13:04:32 +00002550 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002551 }
2552 }
2553 }
2554
Richard S. Hallafc52d42006-02-09 13:04:32 +00002555 return pkgs;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002556 }
2557
2558 /**
2559 * Returns an array of all actively exported packages from the specified
2560 * bundle or if the specified bundle is <tt>null</tt> an array
2561 * containing all actively exported packages by all bundles.
2562 *
2563 * @param b The bundle whose exported packages are to be retrieved
2564 * or <tt>null</tt> if the exported packages of all bundles are
2565 * to be retrieved.
2566 * @return An array of exported packages.
2567 **/
2568 protected ExportedPackage[] getExportedPackages(Bundle b)
2569 {
2570 List list = new ArrayList();
2571
2572 // If a bundle is specified, then return its
2573 // exported packages.
2574 if (b != null)
2575 {
2576 BundleImpl bundle = (BundleImpl) b;
2577 getExportedPackages(bundle, list);
2578 }
2579 // Otherwise return all exported packages.
2580 else
2581 {
2582 // To create a list of all exported packages, we must look
2583 // in the installed and uninstalled sets of bundles. To
2584 // ensure a somewhat consistent view, we will gather all
2585 // of this information from within the installed bundle
2586 // lock.
2587 synchronized (m_installedBundleLock_Priority2)
2588 {
2589 // First get exported packages from uninstalled bundles.
2590 synchronized (m_uninstalledBundlesLock_Priority3)
2591 {
2592 for (int bundleIdx = 0;
2593 (m_uninstalledBundles != null) && (bundleIdx < m_uninstalledBundles.length);
2594 bundleIdx++)
2595 {
2596 BundleImpl bundle = m_uninstalledBundles[bundleIdx];
2597 getExportedPackages(bundle, list);
2598 }
2599 }
2600
2601 // Now get exported packages from installed bundles.
2602 Bundle[] bundles = getBundles();
2603 for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
2604 {
2605 BundleImpl bundle = (BundleImpl) bundles[bundleIdx];
2606 getExportedPackages(bundle, list);
2607 }
2608 }
2609 }
2610
2611 return (ExportedPackage[]) list.toArray(new ExportedPackage[list.size()]);
2612 }
2613
2614 /**
2615 * Adds any current active exported packages from the specified bundle
2616 * to the passed in list.
2617 * @param bundle The bundle from which to retrieve exported packages.
2618 * @param list The list to which the exported packages are added
2619 **/
2620 private void getExportedPackages(BundleImpl bundle, List list)
2621 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002622 // Since a bundle may have many modules associated with it,
2623 // one for each revision in the cache, search each module
2624 // for each revision to get all exports.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002625 IModule[] modules = bundle.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002626 for (int modIdx = 0; modIdx < modules.length; modIdx++)
2627 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002628 R4Export[] exports = m_policyCore.getExports(modules[modIdx]);
2629 if ((exports != null) && (exports.length > 0))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002630 {
2631 for (int expIdx = 0; expIdx < exports.length; expIdx++)
2632 {
2633 // See if the target bundle's module is one of the
2634 // "in use" exporters of the package.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002635 IModule[] inUseModules =
2636 m_policyCore.getInUseExporters(
2637 new R4Import(exports[expIdx].getName(), null, null));
2638 // Search through the current providers to find the target
2639 // module.
2640 for (int i = 0; (inUseModules != null) && (i < inUseModules.length); i++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002641 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002642 if (inUseModules[i] == modules[modIdx])
2643 {
2644 list.add(new ExportedPackageImpl(
Richard S. Hall60c26d42006-07-19 10:35:04 +00002645 this, bundle, modules[modIdx], exports[expIdx]));
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002646 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002647 }
2648 }
2649 }
2650 }
2651 }
2652
2653 protected Bundle[] getImportingBundles(ExportedPackage ep)
2654 {
Richard S. Halle1f53a52006-07-17 11:06:59 +00002655 // Get exporting bundle.
Richard S. Hall930fecc2005-08-16 18:33:34 +00002656 BundleImpl exporter = (BundleImpl)
Richard S. Halle1f53a52006-07-17 11:06:59 +00002657 ((ExportedPackage) ep).getExportingBundle();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002658 BundleInfo exporterInfo = exporter.getInfo();
2659
2660 // Create list for storing importing bundles.
2661 List list = new ArrayList();
2662 Bundle[] bundles = getBundles();
2663
2664 // Check all bundles to see who imports the package.
2665 for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
2666 {
2667 BundleImpl importer = (BundleImpl) bundles[bundleIdx];
2668
2669 // Ignore the bundle if it imports from itself.
2670 if (exporter != importer)
2671 {
2672 // Check the import wires of all modules for all bundles.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002673 IModule[] modules = importer.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002674 for (int modIdx = 0; modIdx < modules.length; modIdx++)
2675 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002676 R4Wire wire = Util.getWire(modules[modIdx], ep.getName());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002677
2678 // If the resolving module is associated with the
2679 // exporting bundle, then add current bundle to
2680 // import list.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002681 if ((wire != null) && exporterInfo.hasModule(wire.getExportingModule()))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002682 {
2683 // Add the bundle to the list of importers.
2684 list.add(bundles[bundleIdx]);
2685 break;
2686 }
2687 }
2688 }
2689 }
2690
2691 // Return the results.
2692 if (list.size() > 0)
2693 {
2694 return (Bundle[]) list.toArray(new Bundle[list.size()]);
2695 }
2696
2697 return null;
2698 }
2699
Richard S. Hall1a4ab602006-05-24 13:46:06 +00002700 protected boolean resolveBundles(Bundle[] targets)
2701 {
2702 if (System.getSecurityManager() != null)
2703 {
2704// TODO: FW SECURITY - Perform proper security check.
2705 AccessController.checkPermission(m_adminPerm);
2706 }
2707
2708 // Acquire locks for all bundles to be resolved.
2709 BundleImpl[] bundles = acquireBundleResolveLocks(targets);
2710
2711 try
2712 {
2713 boolean result = true;
2714
2715 // If there are targets, then resolve each one.
2716 if (bundles != null)
2717 {
2718 for (int i = 0; i < bundles.length; i++)
2719 {
2720 try
2721 {
2722 _resolveBundle(bundles[i]);
2723 }
2724 catch (BundleException ex)
2725 {
2726 result = false;
2727 m_logger.log(
2728 Logger.LOG_WARNING,
2729 "Unable to resolve bundle " + bundles[i].getBundleId(),
2730 ex);
2731 }
2732 }
2733 }
2734
2735 return result;
2736 }
2737 finally
2738 {
2739 // Always release all bundle locks.
2740 releaseBundleLocks(bundles);
2741 }
2742 }
2743
Richard S. Hall930fecc2005-08-16 18:33:34 +00002744 protected void refreshPackages(Bundle[] targets)
2745 {
2746 if (System.getSecurityManager() != null)
2747 {
Richard S. Hall1a4ab602006-05-24 13:46:06 +00002748// TODO: FW SECURITY - Perform proper security check.
Richard S. Hall930fecc2005-08-16 18:33:34 +00002749 AccessController.checkPermission(m_adminPerm);
2750 }
2751
2752 // Acquire locks for all impacted bundles.
2753 BundleImpl[] bundles = acquireBundleRefreshLocks(targets);
2754
2755 // Remove any targeted bundles from the uninstalled bundles
2756 // array, since they will be removed from the system after
2757 // the refresh.
2758 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
2759 {
2760 forgetUninstalledBundle(bundles[i]);
2761 }
2762
2763 try
2764 {
2765 // If there are targets, then refresh each one.
2766 if (bundles != null)
2767 {
2768 // At this point the map contains every bundle that has been
2769 // updated and/or removed as well as all bundles that import
2770 // packages from these bundles.
2771
2772 // Create refresh helpers for each bundle.
2773 RefreshHelper[] helpers = new RefreshHelper[bundles.length];
2774 for (int i = 0; i < bundles.length; i++)
2775 {
2776 helpers[i] = new RefreshHelper(bundles[i]);
2777 }
2778
2779 // Stop, purge or remove, and reinitialize all bundles first.
2780 for (int i = 0; i < helpers.length; i++)
2781 {
2782 helpers[i].stop();
2783 helpers[i].purgeOrRemove();
2784 helpers[i].reinitialize();
2785 }
2786
2787 // Then restart all bundles that were previously running.
2788 for (int i = 0; i < helpers.length; i++)
2789 {
2790 helpers[i].restart();
2791 }
2792 }
2793 }
2794 finally
2795 {
2796 // Always release all bundle locks.
2797 releaseBundleLocks(bundles);
2798 }
2799
2800 fireFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, getBundle(0), null);
2801 }
2802
2803 private void populateImportGraph(BundleImpl target, Map map)
2804 {
2805 // Get the exported packages for the specified bundle.
2806 ExportedPackage[] pkgs = getExportedPackages(target);
2807
2808 for (int pkgIdx = 0; (pkgs != null) && (pkgIdx < pkgs.length); pkgIdx++)
2809 {
2810 // Get all imports of this package.
2811 Bundle[] importers = getImportingBundles(pkgs[pkgIdx]);
2812
2813 for (int impIdx = 0;
2814 (importers != null) && (impIdx < importers.length);
2815 impIdx++)
2816 {
Richard S. Halle34df092005-10-06 17:03:05 +00002817 // Avoid cycles if the bundle is already in map.
2818 if (!map.containsKey(importers[impIdx]))
2819 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002820 // Add each importing bundle to map.
2821 map.put(importers[impIdx], importers[impIdx]);
2822 // Now recurse into each bundle to get its importers.
2823 populateImportGraph(
2824 (BundleImpl) importers[impIdx], map);
Richard S. Halle34df092005-10-06 17:03:05 +00002825 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002826 }
2827 }
2828 }
2829
2830 //
2831 // Miscellaneous private methods.
2832 //
2833
Richard S. Hall04bdbb12006-03-15 14:26:15 +00002834 private BundleInfo createBundleInfo(BundleArchive archive)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002835 throws Exception
2836 {
2837 // Get the bundle manifest.
2838 Map headerMap = null;
2839 try
2840 {
2841 // Although there should only ever be one revision at this
2842 // point, get the header for the current revision to be safe.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00002843 headerMap = archive.getRevision(archive.getRevisionCount() - 1).getManifestHeader();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002844 }
2845 catch (Exception ex)
2846 {
2847 throw new BundleException("Unable to read JAR manifest.", ex);
2848 }
2849
2850 // We can't do anything without the manifest header.
2851 if (headerMap == null)
2852 {
2853 throw new BundleException("Unable to read JAR manifest header.");
2854 }
2855
2856 // Create the module for the bundle; although there should only
2857 // ever be one revision at this point, create the module for
2858 // the current revision to be safe.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002859 IModule module = createModule(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002860 archive.getId(), archive.getRevisionCount() - 1, headerMap);
2861
2862 // Finally, create an return the bundle info.
2863 return new BundleInfo(m_logger, archive, module);
2864 }
2865
2866 /**
2867 * Creates a module for a given bundle by reading the bundle's
2868 * manifest meta-data and converting it to work with the underlying
2869 * import/export search policy of the module loader.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002870 * @param targetId The identifier of the bundle for which the module should
Richard S. Hall930fecc2005-08-16 18:33:34 +00002871 * be created.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002872 * @param headerMap The headers map associated with the bundle.
Richard S. Hall930fecc2005-08-16 18:33:34 +00002873 * @return The initialized and/or newly created module.
2874 **/
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002875 private IModule createModule(long targetId, int revision, Map headerMap)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002876 throws Exception
2877 {
2878 // Get the manifest version.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002879 String manifestVersion = (String) headerMap.get(FelixConstants.BUNDLE_MANIFESTVERSION);
2880 manifestVersion = (manifestVersion == null) ? "1" : manifestVersion;
2881 if (!manifestVersion.equals("1") && !manifestVersion.equals("2"))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002882 {
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002883 throw new BundleException("Unknown 'Bundle-ManifestVersion' value: " + manifestVersion);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002884 }
2885
Richard S. Hallb72001a2006-02-20 15:10:33 +00002886 // Create map to check for duplicate imports/exports.
2887 Map dupeMap = new HashMap();
2888
Richard S. Hall930fecc2005-08-16 18:33:34 +00002889 // Get export packages from bundle manifest.
Richard S. Hallad24d9f2006-07-03 09:09:18 +00002890 R4Package[] pkgs = R4Package.parseImportOrExportHeader(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002891 (String) headerMap.get(Constants.EXPORT_PACKAGE));
Richard S. Hallb72001a2006-02-20 15:10:33 +00002892
2893 // Create non-duplicated export array.
2894 dupeMap.clear();
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002895 for (int i = 0; i < pkgs.length; i++)
2896 {
Richard S. Hallb72001a2006-02-20 15:10:33 +00002897 if (dupeMap.get(pkgs[i].getName()) == null)
2898 {
2899 dupeMap.put(pkgs[i].getName(), new R4Export(pkgs[i]));
2900 }
2901 else
2902 {
2903 // TODO: FRAMEWORK - Exports can be duplicated, so fix this.
2904 m_logger.log(Logger.LOG_WARNING,
2905 "Duplicate export - " + pkgs[i].getName());
2906 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002907 }
Richard S. Hallb72001a2006-02-20 15:10:33 +00002908 R4Export[] exports =
2909 (R4Export[]) dupeMap.values().toArray(new R4Export[dupeMap.size()]);
2910
Richard S. Hallad24d9f2006-07-03 09:09:18 +00002911 // Get import packages from bundle manifest.
2912 pkgs = R4Package.parseImportOrExportHeader(
2913 (String) headerMap.get(Constants.IMPORT_PACKAGE));
Richard S. Hall930fecc2005-08-16 18:33:34 +00002914
Richard S. Hallad24d9f2006-07-03 09:09:18 +00002915 // Create non-duplicated import array.
2916 dupeMap.clear();
2917 for (int i = 0; i < pkgs.length; i++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002918 {
Richard S. Hallad24d9f2006-07-03 09:09:18 +00002919 if (dupeMap.get(pkgs[i].getName()) == null)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002920 {
Richard S. Hallad24d9f2006-07-03 09:09:18 +00002921 dupeMap.put(pkgs[i].getName(), new R4Import(pkgs[i]));
Richard S. Hall930fecc2005-08-16 18:33:34 +00002922 }
Richard S. Hallad24d9f2006-07-03 09:09:18 +00002923 else
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002924 {
Richard S. Hallad24d9f2006-07-03 09:09:18 +00002925 // TODO: FRAMEWORK - Determine if we should error here.
2926 m_logger.log(Logger.LOG_WARNING,
2927 "Duplicate import - " + pkgs[i].getName());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002928 }
2929 }
Richard S. Hallad24d9f2006-07-03 09:09:18 +00002930 R4Import[] imports =
2931 (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.size()]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002932
Richard S. Hall930fecc2005-08-16 18:33:34 +00002933 // Get dynamic import packages from bundle manifest.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002934 pkgs = R4Package.parseImportOrExportHeader(
Richard S. Hall930fecc2005-08-16 18:33:34 +00002935 (String) headerMap.get(Constants.DYNAMICIMPORT_PACKAGE));
Richard S. Hallb72001a2006-02-20 15:10:33 +00002936
2937 // Create non-duplicated dynamic import array.
2938 dupeMap.clear();
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002939 for (int i = 0; i < pkgs.length; i++)
2940 {
Richard S. Hallb72001a2006-02-20 15:10:33 +00002941 if (dupeMap.get(pkgs[i].getName()) == null)
2942 {
2943 dupeMap.put(pkgs[i].getName(), new R4Import(pkgs[i]));
2944 }
2945 else
2946 {
2947 // TODO: FRAMEWORK - Determine if we should error here.
2948 m_logger.log(Logger.LOG_WARNING,
2949 "Duplicate import - " + pkgs[i].getName());
2950 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002951 }
Richard S. Hallb72001a2006-02-20 15:10:33 +00002952 R4Import[] dynamics =
2953 (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.size()]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002954
Richard S. Hall8bebf412006-07-03 12:54:50 +00002955 // Do some validity checking on bundles with R4 headers.
Richard S. Hallc6c4e7e2006-07-03 14:39:55 +00002956// TODO: FRAMEWORK - Perhaps these verifications and conversions can be done more efficiently.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002957 if (manifestVersion.equals("2"))
Richard S. Hall8bebf412006-07-03 12:54:50 +00002958 {
2959 // Verify that bundle symbolic name is specified.
2960 String targetSym = (String) headerMap.get(FelixConstants.BUNDLE_SYMBOLICNAME);
2961 if (targetSym == null)
2962 {
2963 throw new BundleException("R4 bundle manifests must include bundle symbolic name.");
2964 }
Richard S. Hallc6c4e7e2006-07-03 14:39:55 +00002965
Richard S. Hall8bebf412006-07-03 12:54:50 +00002966 // Verify that the bundle symbolic name and version is unique.
2967 String targetVer = (String) headerMap.get(FelixConstants.BUNDLE_VERSION);
2968 targetVer = (targetVer == null) ? "0.0.0" : targetVer;
2969 Bundle[] bundles = getBundles();
2970 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
2971 {
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002972 long id = ((BundleImpl) bundles[i]).getInfo().getBundleId();
Richard S. Hall8bebf412006-07-03 12:54:50 +00002973 String sym = (String) ((BundleImpl) bundles[i])
2974 .getInfo().getCurrentHeader().get(Constants.BUNDLE_SYMBOLICNAME);
2975 String ver = (String) ((BundleImpl) bundles[i])
2976 .getInfo().getCurrentHeader().get(Constants.BUNDLE_VERSION);
2977 ver = (ver == null) ? "0.0.0" : ver;
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002978 if (targetSym.equals(sym) && targetVer.equals(ver) && (targetId != id))
Richard S. Hall8bebf412006-07-03 12:54:50 +00002979 {
2980 throw new BundleException("Bundle symbolic name and version are not unique.");
2981 }
2982 }
Richard S. Hallc6c4e7e2006-07-03 14:39:55 +00002983
2984 // Need to add symbolic name and bundle version to all R4 exports.
2985 for (int i = 0; (exports != null) && (i < exports.length); i++)
2986 {
2987 R4Attribute[] attrs = exports[i].getAttributes();
2988 R4Attribute[] newAttrs = new R4Attribute[attrs.length + 2];
2989 System.arraycopy(attrs, 0, newAttrs, 0, attrs.length);
2990 newAttrs[attrs.length] = new R4Attribute(
2991 Constants.BUNDLE_SYMBOLICNAME_ATTRIBUTE, targetSym, false);
2992 newAttrs[attrs.length + 1] = new R4Attribute(
2993 Constants.BUNDLE_VERSION_ATTRIBUTE, targetVer, false);
2994 exports[i] = new R4Export(
2995 exports[i].getName(), exports[i].getDirectives(), newAttrs);
2996 }
Richard S. Hall8bebf412006-07-03 12:54:50 +00002997 }
2998 // Do some validity checking and conversion on bundles with R3 headers.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00002999 else if (manifestVersion.equals("1"))
Richard S. Hall930fecc2005-08-16 18:33:34 +00003000 {
Richard S. Hallad24d9f2006-07-03 09:09:18 +00003001 // Check to make sure that R3 bundles have only specified
3002 // the 'specification-version' attribute and no directives
3003 // on their exports.
3004 for (int i = 0; (exports != null) && (i < exports.length); i++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003005 {
Richard S. Hallad24d9f2006-07-03 09:09:18 +00003006 if (exports[i].getDirectives().length != 0)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003007 {
Richard S. Hallad24d9f2006-07-03 09:09:18 +00003008 throw new BundleException("R3 exports cannot contain directives.");
Richard S. Hall930fecc2005-08-16 18:33:34 +00003009 }
Richard S. Hallad24d9f2006-07-03 09:09:18 +00003010 // NOTE: This is checking for "version" rather than "specification-version"
3011 // because the package class normalizes to "version" to avoid having
3012 // future special cases. This could be changed if more strict behavior
3013 // is required.
3014 if ((exports[i].getAttributes().length > 1) ||
3015 ((exports[i].getAttributes().length == 1) &&
3016 (!exports[i].getAttributes()[0].getName().equals(FelixConstants.VERSION_ATTRIBUTE))))
Richard S. Hall930fecc2005-08-16 18:33:34 +00003017 {
Richard S. Hallad24d9f2006-07-03 09:09:18 +00003018 throw new BundleException(
Richard S. Hall4c7d68e2006-07-11 13:15:47 +00003019 "Export does not conform to R3 syntax: " + exports[i]);
Richard S. Hallad24d9f2006-07-03 09:09:18 +00003020 }
3021 }
3022
3023 // Check to make sure that R3 bundles have only specified
3024 // the 'specification-version' attribute and no directives
3025 // on their imports.
3026 for (int i = 0; (imports != null) && (i < imports.length); i++)
3027 {
3028 if (imports[i].getDirectives().length != 0)
3029 {
3030 throw new BundleException("R3 imports cannot contain directives.");
3031 }
3032 // NOTE: This is checking for "version" rather than "specification-version"
3033 // because the package class normalizes to "version" to avoid having
3034 // future special cases. This could be changed if more strict behavior
3035 // is required.
3036 if ((imports[i].getVersionHigh() != null) ||
3037 (imports[i].getAttributes().length > 1) ||
3038 ((imports[i].getAttributes().length == 1) &&
3039 (!imports[i].getAttributes()[0].getName().equals(FelixConstants.VERSION_ATTRIBUTE))))
3040 {
3041 throw new BundleException(
3042 "Import does not conform to R3 syntax: " + imports[i]);
3043 }
3044 }
3045
3046 // Since all R3 exports imply an import, add a corresponding
3047 // import for each existing export. Create non-duplicated import array.
3048 dupeMap.clear();
3049 // Add existing imports.
3050 for (int i = 0; i < imports.length; i++)
3051 {
3052 dupeMap.put(imports[i].getName(), imports[i]);
3053 }
3054 // Add import for each export.
3055 for (int i = 0; i < exports.length; i++)
3056 {
3057 if (dupeMap.get(exports[i].getName()) == null)
3058 {
3059 dupeMap.put(exports[i].getName(), new R4Import(exports[i]));
3060 }
3061 }
3062 imports =
3063 (R4Import[]) dupeMap.values().toArray(new R4Import[dupeMap.size()]);
3064
3065 // Add a "uses" directive onto each export of R3 bundles
3066 // that references every other import (which will include
3067 // exports, since export implies import); this is
3068 // necessary since R3 bundles assumed a single class space,
3069 // but R4 allows for multiple class spaces.
3070 String usesValue = "";
3071 for (int i = 0; (imports != null) && (i < imports.length); i++)
3072 {
3073 usesValue = usesValue
3074 + ((usesValue.length() > 0) ? "," : "")
3075 + imports[i].getName();
3076 }
3077 R4Directive uses = new R4Directive(
3078 FelixConstants.USES_DIRECTIVE, usesValue);
3079 for (int i = 0; (exports != null) && (i < exports.length); i++)
3080 {
3081 exports[i] = new R4Export(
3082 exports[i].getName(),
3083 new R4Directive[] { uses },
3084 exports[i].getAttributes());
3085 }
3086
3087 // Check to make sure that R3 bundles have no attributes or
3088 // directives on their dynamic imports.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00003089 for (int i = 0; (dynamics != null) && (i < dynamics.length); i++)
Richard S. Hallad24d9f2006-07-03 09:09:18 +00003090 {
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00003091 if (dynamics[i].getDirectives().length != 0)
Richard S. Hallad24d9f2006-07-03 09:09:18 +00003092 {
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00003093 throw new BundleException("R3 dynamic imports cannot contain directives.");
3094 }
3095 if (dynamics[i].getAttributes().length != 0)
3096 {
3097 throw new BundleException("R3 dynamic imports cannot contain attributes.");
Richard S. Hall930fecc2005-08-16 18:33:34 +00003098 }
3099 }
3100 }
3101
Richard S. Hall930fecc2005-08-16 18:33:34 +00003102 // Get native library entry names for module library sources.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003103 R4LibraryHeader[] libraryHeaders =
Richard S. Hall930fecc2005-08-16 18:33:34 +00003104 Util.parseLibraryStrings(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003105 m_logger,
Richard S. Hall930fecc2005-08-16 18:33:34 +00003106 Util.parseDelimitedString(
3107 (String) headerMap.get(Constants.BUNDLE_NATIVECODE), ","));
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003108 R4Library[] libraries = new R4Library[libraryHeaders.length];
3109 for (int i = 0; i < libraries.length; i++)
3110 {
3111 libraries[i] = new R4Library(
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00003112 m_logger, m_cache, targetId, revision,
Richard S. Hall930fecc2005-08-16 18:33:34 +00003113 getProperty(Constants.FRAMEWORK_OS_NAME),
3114 getProperty(Constants.FRAMEWORK_PROCESSOR),
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003115 libraryHeaders[i]);
3116 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003117
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003118 // Now that we have all of the metadata associated with the
3119 // module, we need to create the module itself. This is somewhat
3120 // complicated because a module is constructed out of several
3121 // interrelated pieces (e.g., content loader, search policy,
3122 // url policy). We need to create all of these pieces and bind
3123 // them together.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003124
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003125 // First, create the module.
3126 IModule module = m_factory.createModule(
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00003127 Long.toString(targetId) + "." + Integer.toString(revision));
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003128 // Attach the R4 search policy metadata to the module.
3129 m_policyCore.setExports(module, exports);
3130 m_policyCore.setImports(module, imports);
3131 m_policyCore.setDynamicImports(module, dynamics);
3132 m_policyCore.setLibraries(module, libraries);
3133
3134 // Create the content loader associated with the module archive.
3135 IContentLoader contentLoader = new ContentLoaderImpl(
3136 m_logger,
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00003137 m_cache.getArchive(targetId).getRevision(revision).getContent(),
3138 m_cache.getArchive(targetId).getRevision(revision).getContentPath());
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003139 // Set the content loader's search policy.
3140 contentLoader.setSearchPolicy(
3141 new R4SearchPolicy(m_policyCore, module));
3142 // Set the content loader's URL policy.
3143 contentLoader.setURLPolicy(
Richard S. Hallfb5221e2006-02-20 10:22:28 +00003144// TODO: ML - SUCKS NEEDING URL POLICY PER MODULE.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003145 new URLPolicyImpl(
3146 m_logger, m_bundleStreamHandler, module));
3147
3148 // Set the module's content loader to the created content loader.
3149 m_factory.setContentLoader(module, contentLoader);
3150
3151 // Done, so return the module.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003152 return module;
3153 }
3154
3155 private BundleActivator createBundleActivator(BundleInfo info)
3156 throws Exception
3157 {
3158 // CONCURRENCY NOTE:
3159 // This method is called indirectly from startBundle() (via _startBundle()),
3160 // which has the exclusion lock, so there is no need to do any locking here.
3161
3162 BundleActivator activator = null;
3163
3164 String strict = m_config.get(FelixConstants.STRICT_OSGI_PROP);
3165 boolean isStrict = (strict == null) ? true : strict.equals("true");
3166 if (!isStrict)
3167 {
3168 try
3169 {
3170 activator =
3171 m_cache.getArchive(info.getBundleId())
Richard S. Hallf1359482006-02-14 08:02:51 +00003172 .getActivator(info.getCurrentModule());
Richard S. Hall930fecc2005-08-16 18:33:34 +00003173 }
3174 catch (Exception ex)
3175 {
3176 activator = null;
3177 }
3178 }
3179
3180 // If there was no cached activator, then get the activator
3181 // class from the bundle manifest.
3182 if (activator == null)
3183 {
3184 // Get the associated bundle archive.
Richard S. Hall04bdbb12006-03-15 14:26:15 +00003185 BundleArchive ba = m_cache.getArchive(info.getBundleId());
Richard S. Hall930fecc2005-08-16 18:33:34 +00003186 // Get the manifest from the current revision; revision is
3187 // base zero so subtract one from the count to get the
3188 // current revision.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00003189 Map headerMap = ba.getRevision(ba.getRevisionCount() - 1).getManifestHeader();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003190 // Get the activator class attribute.
3191 String className = (String) headerMap.get(Constants.BUNDLE_ACTIVATOR);
3192 // Try to instantiate activator class if present.
3193 if (className != null)
3194 {
3195 className = className.trim();
Richard S. Hall6b5f96c2006-02-10 15:57:15 +00003196 Class clazz = info.getCurrentModule().getClass(className);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003197 if (clazz == null)
3198 {
3199 throw new BundleException("Not found: "
Richard S. Hall56c68832006-06-23 15:27:31 +00003200 + className, new ClassNotFoundException(className));
Richard S. Hall930fecc2005-08-16 18:33:34 +00003201 }
3202 activator = (BundleActivator) clazz.newInstance();
3203 }
3204 }
3205
3206 return activator;
3207 }
3208
3209 private void purgeBundle(BundleImpl bundle) throws Exception
3210 {
3211 // Acquire bundle lock.
3212 acquireBundleLock(bundle);
3213
3214 try
3215 {
3216 BundleInfo info = bundle.getInfo();
3217
3218 // In case of a refresh, then we want to physically
3219 // remove the bundle's modules from the module manager.
3220 // This is necessary for two reasons: 1) because
3221 // under Windows we won't be able to delete the bundle
3222 // because files might be left open in the resource
3223 // sources of its modules and 2) we want to make sure
3224 // that no references to old modules exist since they
3225 // will all be stale after the refresh. The only other
3226 // way to do this is to remove the bundle, but that
3227 // would be incorrect, because this is a refresh operation
3228 // and should not trigger bundle REMOVE events.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003229 IModule[] modules = info.getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003230 for (int i = 0; i < modules.length; i++)
3231 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003232 m_factory.removeModule(modules[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003233 }
3234
3235 // Purge all bundle revisions, but the current one.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00003236 m_cache.getArchive(info.getBundleId()).purge();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003237 }
3238 finally
3239 {
3240 // Always release the bundle lock.
3241 releaseBundleLock(bundle);
3242 }
3243 }
3244
3245 private void garbageCollectBundle(BundleImpl bundle) throws Exception
3246 {
3247 // CONCURRENCY NOTE: There is no reason to lock this bundle,
3248 // because this method is only called during shutdown or a
3249 // refresh operation and these are already guarded by locks.
3250
3251 // Remove the bundle's associated modules from
3252 // the module manager.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003253 IModule[] modules = bundle.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003254 for (int i = 0; i < modules.length; i++)
3255 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003256 m_factory.removeModule(modules[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003257 }
3258
3259 // Remove the bundle from the cache.
3260 m_cache.remove(m_cache.getArchive(bundle.getInfo().getBundleId()));
3261 }
3262
3263 //
3264 // Event-related methods.
3265 //
3266
3267 /**
3268 * Fires bundle events.
3269 **/
3270 private void fireFrameworkEvent(
3271 int type, Bundle bundle, Throwable throwable)
3272 {
3273 if (m_frameworkDispatcher == null)
3274 {
3275 m_frameworkDispatcher = new Dispatcher() {
3276 public void dispatch(EventListener l, EventObject eventObj)
3277 {
3278 ((FrameworkListener) l)
3279 .frameworkEvent((FrameworkEvent) eventObj);
3280 }
3281 };
3282 }
3283 FrameworkEvent event = new FrameworkEvent(type, bundle, throwable);
3284 m_dispatchQueue.dispatch(
3285 m_frameworkDispatcher, FrameworkListener.class, event);
3286 }
3287
3288 /**
3289 * Fires bundle events.
3290 *
3291 * @param type The type of bundle event to fire.
3292 * @param bundle The bundle associated with the event.
3293 **/
3294 private void fireBundleEvent(int type, Bundle bundle)
3295 {
3296 if (m_bundleDispatcher == null)
3297 {
3298 m_bundleDispatcher = new Dispatcher() {
3299 public void dispatch(EventListener l, EventObject eventObj)
3300 {
3301 ((BundleListener) l)
3302 .bundleChanged((BundleEvent) eventObj);
3303 }
3304 };
3305 }
3306 BundleEvent event = null;
3307 event = new BundleEvent(type, bundle);
3308 m_dispatchQueue.dispatch(m_bundleDispatcher,
3309 BundleListener.class, event);
3310 }
3311
3312 /**
3313 * Fires service events.
3314 *
3315 * @param type The type of service event to fire.
3316 * @param ref The service reference associated with the event.
3317 **/
3318 private void fireServiceEvent(ServiceEvent event)
3319 {
3320 if (m_serviceDispatcher == null)
3321 {
3322 m_serviceDispatcher = new Dispatcher() {
3323 public void dispatch(EventListener l, EventObject eventObj)
3324 {
3325// TODO: Filter service events based on service permissions.
3326 if (l instanceof ListenerWrapper)
3327 {
3328 BundleImpl bundle = (BundleImpl) ((ServiceListenerWrapper) l).getBundle();
3329 if (isServiceAssignable(bundle, ((ServiceEvent) eventObj).getServiceReference()))
3330 {
3331 ((ServiceListener) l)
3332 .serviceChanged((ServiceEvent) eventObj);
3333 }
3334 }
3335 else
3336 {
3337 ((ServiceListener) l)
3338 .serviceChanged((ServiceEvent) eventObj);
3339 }
3340 }
3341 };
3342 }
3343 m_dispatchQueue.dispatch(m_serviceDispatcher,
3344 ServiceListener.class, event);
3345 }
3346
3347 //
3348 // Property related methods.
3349 //
3350
3351 private void initializeFrameworkProperties()
3352 {
3353 // Standard OSGi properties.
Richard S. Hallea415752005-12-05 19:30:28 +00003354 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003355 FelixConstants.FRAMEWORK_VERSION,
3356 FelixConstants.FRAMEWORK_VERSION_VALUE);
Richard S. Hallea415752005-12-05 19:30:28 +00003357 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003358 FelixConstants.FRAMEWORK_VENDOR,
3359 FelixConstants.FRAMEWORK_VENDOR_VALUE);
Richard S. Hallea415752005-12-05 19:30:28 +00003360 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003361 FelixConstants.FRAMEWORK_LANGUAGE,
3362 System.getProperty("user.language"));
Richard S. Hallea415752005-12-05 19:30:28 +00003363 m_configMutable.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003364 FelixConstants.FRAMEWORK_OS_VERSION,
3365 System.getProperty("os.version"));
3366
3367 String s = null;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003368 s = R4Library.normalizePropertyValue(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003369 FelixConstants.FRAMEWORK_OS_NAME,
3370 System.getProperty("os.name"));
Richard S. Hallea415752005-12-05 19:30:28 +00003371 m_configMutable.put(FelixConstants.FRAMEWORK_OS_NAME, s);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003372 s = R4Library.normalizePropertyValue(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003373 FelixConstants.FRAMEWORK_PROCESSOR,
3374 System.getProperty("os.arch"));
Richard S. Hallea415752005-12-05 19:30:28 +00003375 m_configMutable.put(FelixConstants.FRAMEWORK_PROCESSOR, s);
Richard S. Hallea415752005-12-05 19:30:28 +00003376 m_configMutable.put(
Richard S. Hall03ddc842006-03-09 14:50:16 +00003377 FelixConstants.FELIX_VERSION_PROPERTY, getFrameworkVersion());
Richard S. Hall930fecc2005-08-16 18:33:34 +00003378 }
3379
Richard S. Hall03ddc842006-03-09 14:50:16 +00003380 /**
3381 * Read the framework version from the property file.
3382 * @return the framework version as a string.
3383 **/
3384 private static String getFrameworkVersion()
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003385 {
3386 // The framework version property.
3387 Properties props = new Properties();
Richard S. Hall03ddc842006-03-09 14:50:16 +00003388 InputStream in = Felix.class.getResourceAsStream("Felix.properties");
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003389 try
3390 {
Richard S. Hall03ddc842006-03-09 14:50:16 +00003391 props.load(in);
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003392 }
Richard S. Hall03ddc842006-03-09 14:50:16 +00003393 catch (IOException ex)
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003394 {
Richard S. Hall03ddc842006-03-09 14:50:16 +00003395 ex.printStackTrace();
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003396 }
Richard S. Halla155e2e2006-03-09 21:20:02 +00003397
3398 // Maven uses a '-' to separate the version qualifier,
3399 // while OSGi uses a '.', so we need to convert to a '.'
3400 StringBuffer sb =
3401 new StringBuffer(
3402 props.getProperty(
3403 FelixConstants.FELIX_VERSION_PROPERTY, "unknown"));
Richard S. Hall1615e552006-05-30 14:10:06 +00003404 if (sb.toString().indexOf("-") >= 0)
Richard S. Halla155e2e2006-03-09 21:20:02 +00003405 {
Richard S. Hall1615e552006-05-30 14:10:06 +00003406 sb.setCharAt(sb.toString().indexOf("-"), '.');
Richard S. Halla155e2e2006-03-09 21:20:02 +00003407 }
3408 return sb.toString();
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003409 }
3410
Richard S. Hall930fecc2005-08-16 18:33:34 +00003411 private void processAutoProperties()
3412 {
3413 // The auto-install property specifies a space-delimited list of
3414 // bundle URLs to be automatically installed into each new profile;
3415 // the start level to which the bundles are assigned is specified by
3416 // appending a ".n" to the auto-install property name, where "n" is
3417 // the desired start level for the list of bundles.
3418 String[] keys = m_config.getKeys();
3419 for (int i = 0; (keys != null) && (i < keys.length); i++)
3420 {
3421 if (keys[i].startsWith(FelixConstants.AUTO_INSTALL_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 {
3448 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003449 Logger.LOG_ERROR, "Auto-properties install.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003450 }
3451 }
3452 }
3453 while (location != null);
3454 }
3455 }
3456 }
3457
3458 // The auto-start property specifies a space-delimited list of
3459 // bundle URLs to be automatically installed and started into each
3460 // new profile; the start level to which the bundles are assigned
3461 // is specified by appending a ".n" to the auto-start property name,
3462 // where "n" is the desired start level for the list of bundles.
3463 // The following code starts bundles in two passes, first it installs
3464 // them, then it starts them.
3465 for (int i = 0; (keys != null) && (i < keys.length); i++)
3466 {
3467 if (keys[i].startsWith(FelixConstants.AUTO_START_PROP))
3468 {
3469 int startLevel = 1;
3470 try
3471 {
3472 startLevel = Integer.parseInt(keys[i].substring(keys[i].lastIndexOf('.') + 1));
3473 }
3474 catch (NumberFormatException ex)
3475 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003476 m_logger.log(Logger.LOG_ERROR, "Invalid property: " + keys[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003477 }
3478 StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
3479 if (st.countTokens() > 0)
3480 {
3481 String location = null;
3482 do
3483 {
3484 location = nextLocation(st);
3485 if (location != null)
3486 {
3487 try
3488 {
3489 BundleImpl b = (BundleImpl) installBundle(location, null);
3490 b.getInfo().setStartLevel(startLevel);
3491 }
3492 catch (Exception ex)
3493 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003494 m_logger.log(Logger.LOG_ERROR, "Auto-properties install.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003495 }
3496 }
3497 }
3498 while (location != null);
3499 }
3500 }
3501 }
3502
3503 // Now loop through and start the installed bundles.
3504 for (int i = 0; (keys != null) && (i < keys.length); i++)
3505 {
3506 if (keys[i].startsWith(FelixConstants.AUTO_START_PROP))
3507 {
3508 StringTokenizer st = new StringTokenizer(m_config.get(keys[i]), "\" ",true);
3509 if (st.countTokens() > 0)
3510 {
3511 String location = null;
3512 do
3513 {
3514 location = nextLocation(st);
3515 if (location != null)
3516 {
3517 // Installing twice just returns the same bundle.
3518 try
3519 {
3520 BundleImpl bundle = (BundleImpl) installBundle(location, null);
3521 if (bundle != null)
3522 {
3523 startBundle(bundle, true);
3524 }
3525 }
3526 catch (Exception ex)
3527 {
3528 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003529 Logger.LOG_ERROR, "Auto-properties start.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003530 }
3531 }
3532 }
3533 while (location != null);
3534 }
3535 }
3536 }
3537 }
3538
3539 private String nextLocation(StringTokenizer st)
3540 {
3541 String retVal = null;
3542
3543 if (st.countTokens() > 0)
3544 {
3545 String tokenList = "\" ";
3546 StringBuffer tokBuf = new StringBuffer(10);
3547 String tok = null;
3548 boolean inQuote = false;
3549 boolean tokStarted = false;
3550 boolean exit = false;
3551 while ((st.hasMoreTokens()) && (!exit))
3552 {
3553 tok = st.nextToken(tokenList);
3554 if (tok.equals("\""))
3555 {
3556 inQuote = ! inQuote;
3557 if (inQuote)
3558 {
3559 tokenList = "\"";
3560 }
3561 else
3562 {
3563 tokenList = "\" ";
3564 }
3565
3566 }
3567 else if (tok.equals(" "))
3568 {
3569 if (tokStarted)
3570 {
3571 retVal = tokBuf.toString();
3572 tokStarted=false;
3573 tokBuf = new StringBuffer(10);
3574 exit = true;
3575 }
3576 }
3577 else
3578 {
3579 tokStarted = true;
3580 tokBuf.append(tok.trim());
3581 }
3582 }
3583
3584 // Handle case where end of token stream and
3585 // still got data
3586 if ((!exit) && (tokStarted))
3587 {
3588 retVal = tokBuf.toString();
3589 }
3590 }
3591
3592 return retVal;
3593 }
3594
3595 //
3596 // Private utility methods.
3597 //
3598
3599 /**
3600 * Generated the next valid bundle identifier.
3601 **/
Richard S. Hall441c7152006-02-17 11:07:10 +00003602 private long getNextId()
Richard S. Hall930fecc2005-08-16 18:33:34 +00003603 {
Richard S. Hall441c7152006-02-17 11:07:10 +00003604 synchronized (m_nextIdLock)
3605 {
3606 return m_nextId++;
3607 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003608 }
3609
3610 //
3611 // Configuration methods and inner classes.
3612 //
3613
3614 public PropertyResolver getConfig()
3615 {
3616 return m_config;
3617 }
3618
3619 private class ConfigImpl implements PropertyResolver
3620 {
3621 public String get(String key)
3622 {
Richard S. Hallea415752005-12-05 19:30:28 +00003623 return (m_configMutable == null) ? null : m_configMutable.get(key);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003624 }
3625
3626 public String[] getKeys()
3627 {
Richard S. Hallea415752005-12-05 19:30:28 +00003628 return m_configMutable.getKeys();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003629 }
3630 }
3631
3632 //
3633 // Logging methods and inner classes.
3634 //
3635
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003636 public Logger getLogger()
Richard S. Hall930fecc2005-08-16 18:33:34 +00003637 {
3638 return m_logger;
3639 }
3640
3641 /**
3642 * Simple class that is used in <tt>refreshPackages()</tt> to embody
3643 * the refresh logic in order to keep the code clean. This class is
3644 * not static because it needs access to framework event firing methods.
3645 **/
3646 private class RefreshHelper
3647 {
3648 private BundleImpl m_bundle = null;
3649
3650 public RefreshHelper(Bundle bundle)
3651 {
3652 m_bundle = (BundleImpl) bundle;
3653 }
3654
3655 public void stop()
3656 {
3657 if (m_bundle.getInfo().getState() == Bundle.ACTIVE)
3658 {
3659 try
3660 {
3661 stopBundle(m_bundle, false);
3662 }
3663 catch (BundleException ex)
3664 {
3665 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3666 }
3667 }
3668 }
3669
3670 public void purgeOrRemove()
3671 {
3672 try
3673 {
3674 BundleInfo info = m_bundle.getInfo();
3675
Richard S. Halle1f53a52006-07-17 11:06:59 +00003676 // Mark the bundle as stale.
3677 info.setStale();
3678
Richard S. Hall930fecc2005-08-16 18:33:34 +00003679 // Remove or purge the bundle depending on its
3680 // current state.
3681 if (info.getState() == Bundle.UNINSTALLED)
3682 {
3683 // This physically removes the bundle from memory
3684 // as well as the bundle cache.
3685 garbageCollectBundle(m_bundle);
3686 m_bundle = null;
3687 }
3688 else
3689 {
3690 // This physically removes all old revisions of the
3691 // bundle from memory and only maintains the newest
3692 // version in the bundle cache.
3693 purgeBundle(m_bundle);
3694 }
3695 }
3696 catch (Exception ex)
3697 {
3698 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3699 }
3700 }
3701
3702 public void reinitialize()
3703 {
3704 if (m_bundle != null)
3705 {
3706 try
3707 {
3708 BundleInfo info = m_bundle.getInfo();
3709 BundleInfo newInfo = createBundleInfo(info.getArchive());
3710 newInfo.syncLock(info);
3711 m_bundle.setInfo(newInfo);
3712 }
3713 catch (Exception ex)
3714 {
3715 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3716 }
3717 }
3718 }
3719
3720 public void restart()
3721 {
3722 if (m_bundle != null)
3723 {
3724 try
3725 {
3726 startBundle(m_bundle, false);
3727 }
3728 catch (BundleException ex)
3729 {
3730 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3731 }
3732 }
3733 }
3734 }
3735
3736 //
3737 // Locking related methods.
3738 //
3739
3740 private void rememberUninstalledBundle(BundleImpl bundle)
3741 {
3742 synchronized (m_uninstalledBundlesLock_Priority3)
3743 {
3744 // Verify that the bundle is not already in the array.
3745 for (int i = 0;
3746 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
3747 i++)
3748 {
3749 if (m_uninstalledBundles[i] == bundle)
3750 {
3751 return;
3752 }
3753 }
3754
3755 if (m_uninstalledBundles != null)
3756 {
3757 BundleImpl[] newBundles =
3758 new BundleImpl[m_uninstalledBundles.length + 1];
3759 System.arraycopy(m_uninstalledBundles, 0,
3760 newBundles, 0, m_uninstalledBundles.length);
3761 newBundles[m_uninstalledBundles.length] = bundle;
3762 m_uninstalledBundles = newBundles;
3763 }
3764 else
3765 {
3766 m_uninstalledBundles = new BundleImpl[] { bundle };
3767 }
3768 }
3769 }
3770
3771 private void forgetUninstalledBundle(BundleImpl bundle)
3772 {
3773 synchronized (m_uninstalledBundlesLock_Priority3)
3774 {
3775 if (m_uninstalledBundles == null)
3776 {
3777 return;
3778 }
3779
3780 int idx = -1;
3781 for (int i = 0; i < m_uninstalledBundles.length; i++)
3782 {
3783 if (m_uninstalledBundles[i] == bundle)
3784 {
3785 idx = i;
3786 break;
3787 }
3788 }
3789
3790 if (idx >= 0)
3791 {
3792 // If this is the only bundle, then point to empty list.
3793 if ((m_uninstalledBundles.length - 1) == 0)
3794 {
3795 m_uninstalledBundles = new BundleImpl[0];
3796 }
3797 // Otherwise, we need to do some array copying.
3798 else
3799 {
3800 BundleImpl[] newBundles =
3801 new BundleImpl[m_uninstalledBundles.length - 1];
3802 System.arraycopy(m_uninstalledBundles, 0, newBundles, 0, idx);
3803 if (idx < newBundles.length)
3804 {
3805 System.arraycopy(
3806 m_uninstalledBundles, idx + 1,
3807 newBundles, idx, newBundles.length - idx);
3808 }
3809 m_uninstalledBundles = newBundles;
3810 }
3811 }
3812 }
3813 }
3814
3815 protected void acquireInstallLock(String location)
3816 throws BundleException
3817 {
3818 synchronized (m_installRequestLock_Priority1)
3819 {
3820 while (m_installRequestMap.get(location) != null)
3821 {
3822 try
3823 {
3824 m_installRequestLock_Priority1.wait();
3825 }
3826 catch (InterruptedException ex)
3827 {
3828 throw new BundleException("Unable to install, thread interrupted.");
3829 }
3830 }
3831
3832 m_installRequestMap.put(location, location);
3833 }
3834 }
3835
3836 protected void releaseInstallLock(String location)
3837 {
3838 synchronized (m_installRequestLock_Priority1)
3839 {
3840 m_installRequestMap.remove(location);
3841 m_installRequestLock_Priority1.notifyAll();
3842 }
3843 }
3844
3845 protected void acquireBundleLock(BundleImpl bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003846 {
3847 synchronized (m_bundleLock)
3848 {
3849 while (!bundle.getInfo().isLockable())
3850 {
3851 try
3852 {
3853 m_bundleLock.wait();
3854 }
3855 catch (InterruptedException ex)
3856 {
3857 // Ignore and just keep waiting.
3858 }
3859 }
3860 bundle.getInfo().lock();
3861 }
3862 }
3863
Richard S. Hall3c26cc02006-02-17 13:51:21 +00003864 protected boolean acquireBundleLockOrFail(BundleImpl bundle)
3865 {
3866 synchronized (m_bundleLock)
3867 {
3868 if (!bundle.getInfo().isLockable())
3869 {
3870 return false;
3871 }
3872 bundle.getInfo().lock();
3873 return true;
3874 }
3875 }
3876
Richard S. Hall930fecc2005-08-16 18:33:34 +00003877 protected void releaseBundleLock(BundleImpl bundle)
3878 {
3879 synchronized (m_bundleLock)
3880 {
3881 bundle.getInfo().unlock();
3882 m_bundleLock.notifyAll();
3883 }
3884 }
3885
Richard S. Hall1a4ab602006-05-24 13:46:06 +00003886 protected BundleImpl[] acquireBundleResolveLocks(Bundle[] targets)
3887 {
3888 // Hold bundles to be locked.
3889 BundleImpl[] bundles = null;
3890 // Convert existing target bundle array to bundle impl array.
3891 if (targets != null)
3892 {
3893 bundles = new BundleImpl[targets.length];
3894 for (int i = 0; i < targets.length; i++)
3895 {
3896 bundles[i] = (BundleImpl) targets[i];
3897 }
3898 }
3899
3900 synchronized (m_bundleLock)
3901 {
3902 boolean success = false;
3903 while (!success)
3904 {
3905 // If targets is null, then resolve all unresolved bundles.
3906 if (targets == null)
3907 {
3908 List list = new ArrayList();
3909
3910 // Add all unresolved bundles to the list.
3911 synchronized (m_installedBundleLock_Priority2)
3912 {
3913 Iterator iter = m_installedBundleMap.values().iterator();
3914 while (iter.hasNext())
3915 {
3916 BundleImpl bundle = (BundleImpl) iter.next();
3917 if (bundle.getInfo().getState() == Bundle.INSTALLED)
3918 {
3919 list.add(bundle);
3920 }
3921 }
3922 }
3923
3924 // Create an array.
3925 if (list.size() > 0)
3926 {
3927 bundles = (BundleImpl[]) list.toArray(new BundleImpl[list.size()]);
3928 }
3929 }
3930
3931 // Check if all unresolved bundles can be locked.
3932 boolean lockable = true;
3933 if (bundles != null)
3934 {
3935 for (int i = 0; lockable && (i < bundles.length); i++)
3936 {
3937 lockable = bundles[i].getInfo().isLockable();
3938 }
3939
3940 // If we can lock all bundles, then lock them.
3941 if (lockable)
3942 {
3943 for (int i = 0; i < bundles.length; i++)
3944 {
3945 bundles[i].getInfo().lock();
3946 }
3947 success = true;
3948 }
3949 // Otherwise, wait and try again.
3950 else
3951 {
3952 try
3953 {
3954 m_bundleLock.wait();
3955 }
3956 catch (InterruptedException ex)
3957 {
3958 // Ignore and just keep waiting.
3959 }
3960 }
3961 }
3962 else
3963 {
3964 // If there were no bundles to lock, then we can just
3965 // exit the lock loop.
3966 success = true;
3967 }
3968 }
3969 }
3970
3971 return bundles;
3972 }
3973
Richard S. Hall930fecc2005-08-16 18:33:34 +00003974 protected BundleImpl[] acquireBundleRefreshLocks(Bundle[] targets)
3975 {
3976 // Hold bundles to be locked.
3977 BundleImpl[] bundles = null;
3978
3979 synchronized (m_bundleLock)
3980 {
3981 boolean success = false;
3982 while (!success)
3983 {
3984 // If targets is null, then refresh all pending bundles.
3985 Bundle[] newTargets = targets;
3986 if (newTargets == null)
3987 {
3988 List list = new ArrayList();
3989
3990 // First add all uninstalled bundles.
3991 synchronized (m_uninstalledBundlesLock_Priority3)
3992 {
3993 for (int i = 0;
3994 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
3995 i++)
3996 {
3997 list.add(m_uninstalledBundles[i]);
3998 }
3999 }
4000
4001 // Then add all updated bundles.
4002 synchronized (m_installedBundleLock_Priority2)
4003 {
4004 Iterator iter = m_installedBundleMap.values().iterator();
4005 while (iter.hasNext())
4006 {
4007 BundleImpl bundle = (BundleImpl) iter.next();
Richard S. Hall60c26d42006-07-19 10:35:04 +00004008 if (bundle.getInfo().getArchive().getRevisionCount() > 1)
Richard S. Hall930fecc2005-08-16 18:33:34 +00004009 {
4010 list.add(bundle);
4011 }
4012 }
4013 }
4014
4015 // Create an array.
4016 if (list.size() > 0)
4017 {
4018 newTargets = (Bundle[]) list.toArray(new Bundle[list.size()]);
4019 }
4020 }
4021
4022 // If there are targets, then find all dependencies
4023 // for each one.
4024 if (newTargets != null)
4025 {
4026 // Create map of bundles that import the packages
4027 // from the target bundles.
4028 Map map = new HashMap();
4029 for (int targetIdx = 0; targetIdx < newTargets.length; targetIdx++)
4030 {
4031 // Add the current target bundle to the map of
4032 // bundles to be refreshed.
4033 BundleImpl target = (BundleImpl) newTargets[targetIdx];
4034 map.put(target, target);
4035 // Add all importing bundles to map.
4036 populateImportGraph(target, map);
4037 }
4038
4039 bundles = (BundleImpl[]) map.values().toArray(new BundleImpl[map.size()]);
4040 }
4041
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004042 // Check if all corresponding bundles can be locked.
Richard S. Hall930fecc2005-08-16 18:33:34 +00004043 boolean lockable = true;
4044 if (bundles != null)
4045 {
4046 for (int i = 0; lockable && (i < bundles.length); i++)
4047 {
4048 lockable = bundles[i].getInfo().isLockable();
4049 }
4050
4051 // If we can lock all bundles, then lock them.
4052 if (lockable)
4053 {
4054 for (int i = 0; i < bundles.length; i++)
4055 {
4056 bundles[i].getInfo().lock();
4057 }
4058 success = true;
4059 }
4060 // Otherwise, wait and try again.
4061 else
4062 {
4063 try
4064 {
4065 m_bundleLock.wait();
4066 }
4067 catch (InterruptedException ex)
4068 {
4069 // Ignore and just keep waiting.
4070 }
4071 }
4072 }
4073 else
4074 {
4075 // If there were no bundles to lock, then we can just
4076 // exit the lock loop.
4077 success = true;
4078 }
4079 }
4080 }
4081
4082 return bundles;
4083 }
4084
4085 protected void releaseBundleLocks(BundleImpl[] bundles)
4086 {
4087 // Always unlock any locked bundles.
4088 synchronized (m_bundleLock)
4089 {
4090 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
4091 {
4092 bundles[i].getInfo().unlock();
4093 }
4094 m_bundleLock.notifyAll();
4095 }
4096 }
Richard S. Hall9a3e9852006-03-04 03:44:05 +00004097}