blob: b26a3dbed19ce6e980cf12f38755177f53889514 [file] [log] [blame]
Karl Pauls49400ec2007-02-12 23:49:43 +00001/*
Richard S. Hallb3951672006-09-19 17:04:53 +00002 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
Richard S. Hall930fecc2005-08-16 18:33:34 +00009 *
Richard S. Hallb3951672006-09-19 17:04:53 +000010 * http://www.apache.org/licenses/LICENSE-2.0
Richard S. Hall930fecc2005-08-16 18:33:34 +000011 *
Richard S. Hallb3951672006-09-19 17:04:53 +000012 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
Richard S. Hall930fecc2005-08-16 18:33:34 +000018 */
Richard S. Hall5a031592005-08-19 19:53:58 +000019package org.apache.felix.framework;
Richard S. Hall930fecc2005-08-16 18:33:34 +000020
Richard S. Hall70855402008-10-10 13:12:44 +000021import org.osgi.framework.launch.SystemBundle;
Richard S. Hall930fecc2005-08-16 18:33:34 +000022import java.io.*;
Karl Pauls49400ec2007-02-12 23:49:43 +000023import java.net.*;
Karl Pauls9a96b152007-01-22 16:35:58 +000024import java.security.*;
Richard S. Hall930fecc2005-08-16 18:33:34 +000025import java.util.*;
Richard S. Hall05fd75e2007-01-18 01:36:45 +000026
27import org.apache.felix.framework.cache.*;
Karl Pauls28636dc2008-02-03 21:32:48 +000028import org.apache.felix.framework.ext.SecurityProvider;
Richard S. Hall5a031592005-08-19 19:53:58 +000029import org.apache.felix.framework.searchpolicy.*;
30import org.apache.felix.framework.util.*;
Richard S. Hall78605422006-12-18 20:47:55 +000031import org.apache.felix.framework.util.manifestparser.*;
Richard S. Hall5a031592005-08-19 19:53:58 +000032import org.apache.felix.moduleloader.*;
Richard S. Hall930fecc2005-08-16 18:33:34 +000033import org.osgi.framework.*;
34import org.osgi.service.packageadmin.ExportedPackage;
Richard S. Hall17897152006-03-02 13:43:09 +000035import org.osgi.service.startlevel.StartLevel;
Richard S. Hall930fecc2005-08-16 18:33:34 +000036
Richard S. Hallafb4ab42008-10-08 21:18:29 +000037public class Felix extends FelixBundle implements SystemBundle
Richard S. Hall930fecc2005-08-16 18:33:34 +000038{
Karl Pauls1bab5662007-06-20 22:33:26 +000039 // The secure action used to do privileged calls
40 static SecureAction m_secureAction = new SecureAction();
Richard S. Hall26b91982007-07-04 21:15:05 +000041
42 // The extension manager to handle extension bundles
Karl Pauls758c2be2008-03-05 13:10:04 +000043 ExtensionManager m_extensionManager;
Karl Paulsad142d22007-09-16 19:53:22 +000044
Richard S. Hall930fecc2005-08-16 18:33:34 +000045 // Logging related member variables.
Richard S. Hall3875d692008-06-24 19:47:44 +000046 private Logger m_logger = null;
Richard S. Hall471e3e62007-07-11 19:25:33 +000047 // Immutable config properties.
48 private Map m_configMap = null;
49 // Mutable configuration properties passed into constructor.
50 private Map m_configMutableMap = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000051
Richard S. Hall29a4fbc2006-02-03 12:54:52 +000052 // MODULE FACTORY.
53 private IModuleFactory m_factory = null;
54 private R4SearchPolicyCore m_policyCore = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000055
56 // Object used as a lock when calculating which bundles
57 // when performing an operation on one or more bundles.
58 private Object[] m_bundleLock = new Object[0];
59
60 // Maps a bundle location to a bundle location;
61 // used to reserve a location when installing a bundle.
Richard S. Halle60d8782007-08-17 20:10:27 +000062 private Map m_installRequestMap = new HashMap();
Richard S. Hall930fecc2005-08-16 18:33:34 +000063 // This lock must be acquired to modify m_installRequestMap;
64 // to help avoid deadlock this lock as priority 1 and should
65 // be acquired before locks with lower priority.
66 private Object[] m_installRequestLock_Priority1 = new Object[0];
67
68 // Maps a bundle location to a bundle.
Richard S. Hallafb4ab42008-10-08 21:18:29 +000069 private HashMap m_installedBundleMap;
70 private SortedMap m_installedBundleIndex;
Richard S. Hall930fecc2005-08-16 18:33:34 +000071 // This lock must be acquired to modify m_installedBundleMap;
72 // to help avoid deadlock this lock as priority 2 and should
73 // be acquired before locks with lower priority.
74 private Object[] m_installedBundleLock_Priority2 = new Object[0];
75
76 // An array of uninstalled bundles before a refresh occurs.
Richard S. Hall26b91982007-07-04 21:15:05 +000077 private FelixBundle[] m_uninstalledBundles = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000078 // This lock must be acquired to modify m_uninstalledBundles;
79 // to help avoid deadlock this lock as priority 3 and should
80 // be acquired before locks with lower priority.
81 private Object[] m_uninstalledBundlesLock_Priority3 = new Object[0];
82
Richard S. Hall930fecc2005-08-16 18:33:34 +000083 // Framework's active start level.
84 private int m_activeStartLevel =
85 FelixConstants.FRAMEWORK_INACTIVE_STARTLEVEL;
86
87 // Local file system cache.
Richard S. Hall04bdbb12006-03-15 14:26:15 +000088 private BundleCache m_cache = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +000089
Richard S. Hall26b91982007-07-04 21:15:05 +000090 // System bundle bundle info instance.
Richard S. Hallafb4ab42008-10-08 21:18:29 +000091 private BundleInfo m_sbi;
92
Richard S. Hall26b91982007-07-04 21:15:05 +000093 // System bundle activator list.
94 List m_activatorList = null;
Richard S. Hall26b91982007-07-04 21:15:05 +000095
Richard S. Hall930fecc2005-08-16 18:33:34 +000096 // Next available bundle identifier.
97 private long m_nextId = 1L;
Richard S. Hall441c7152006-02-17 11:07:10 +000098 private Object m_nextIdLock = new Object[0];
Richard S. Hall930fecc2005-08-16 18:33:34 +000099
100 // List of event listeners.
Richard S. Hall92770632006-07-24 10:18:52 +0000101 private EventDispatcher m_dispatcher = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +0000102
103 // Service registry.
104 private ServiceRegistry m_registry = null;
105
Richard S. Hall29a4fbc2006-02-03 12:54:52 +0000106 // Reusable bundle URL stream handler.
107 private URLStreamHandler m_bundleStreamHandler = null;
108
Richard S. Hall9955e902007-01-25 14:42:01 +0000109 // Execution environment.
110 private String m_executionEnvironment = "";
111 private Set m_executionEnvironmentCache = new HashSet();
112
Richard S. Hall26b91982007-07-04 21:15:05 +0000113 // Shutdown thread.
114 private Thread m_shutdownThread = null;
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000115 private ThreadGate m_shutdownGate = null;
Richard S. Hallc7a576d2007-12-19 22:34:23 +0000116
117 /**
Richard S. Hall930fecc2005-08-16 18:33:34 +0000118 * <p>
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000119 * This constructor creates a framework instance with a specified <tt>Map</tt>
120 * of configuration properties. Configuration properties are used internally
121 * by the framework to alter its default behavior. The configuration properties
122 * should have a <tt>String</tt> key and an <tt>Object</tt> value. The passed
123 * in <tt>Map</tt> is copied by the framework and all keys are converted to
124 * <tt>String</tt>s.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000125 * </p>
126 * <p>
127 * Configuration properties are the sole means to configure the framework's
128 * default behavior; the framework does not refer to any system properties for
Richard S. Hall471e3e62007-07-11 19:25:33 +0000129 * configuration information. If a <tt>Map</tt> is supplied to this method
130 * for configuration properties, then the framework will consult the
131 * <tt>Map</tt> instance for any and all configuration properties. It is
132 * possible to specify a <tt>null</tt> for the configuration property map,
133 * in which case the framework will use its default behavior in all cases.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000134 * </p>
135 * <p>
136 * The following configuration properties can be specified:
137 * </p>
138 * <ul>
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000139 * <li><tt>felix.systembundle.activators</tt> - A <tt>List</tt> of
140 * <tt>BundleActivator</tt> instances that are started/stopped when
141 * the System Bundle is started/stopped; the specified instances will
142 * receive the System Bundle's <tt>BundleContext</tt> when invoked.
143 * </li>
144 * <li><tt>felix.log.logger</tt> - An instance of <tt>Logger</tt> that the
145 * framework uses as its default logger.
146 * </li>
Richard S. Hall5aa58c62006-12-08 17:08:14 +0000147 * <li><tt>felix.log.level</tt> - An integer value indicating the degree
148 * of logging reported by the framework; the higher the value the more
149 * logging is reported. If zero ('0') is specified, then logging is
150 * turned off completely. The log levels match those specified in the
151 * OSGi Log Service (i.e., 1 = error, 2 = warning, 3 = information,
152 * and 4 = debug). The default value is 1.
153 * </li>
Richard S. Hall930fecc2005-08-16 18:33:34 +0000154 * <li><tt>felix.startlevel.framework</tt> - The initial start level
155 * of the framework once it starts execution; the default
156 * value is 1.
157 * </li>
158 * <li><tt>felix.startlevel.bundle</tt> - The default start level for
159 * newly installed bundles; the default value is 1.
160 * </li>
Richard S. Hall5d226732005-11-08 09:09:05 +0000161 * <li><tt>framework.service.urlhandlers</tt> - Flag to indicate whether
162 * to activate the URL Handlers service for the framework instance;
163 * the default value is "<tt>true</tt>". Activating the URL Handlers
164 * service will result in the <tt>URL.setURLStreamHandlerFactory()</tt>
165 * and <tt>URLConnection.setContentHandlerFactory()</tt> being called.
166 * </li>
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000167 * <li><tt>felix.cache.bufsize</tt> - Sets the buffer size to be used by
168 * the cache; the default value is 4096. The integer
169 * value of this string provides control over the size of the
170 * internal buffer of the disk cache for performance reasons.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000171 * </li>
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000172 * <li><tt>felix.cache.dir</tt> - Sets the directory to be used by the
173 * cache as its cache directory. The cache directory is where all
174 * profile directories are stored and a profile directory is where a
175 * set of installed bundles are stored. By default, the cache
176 * directory is <tt>.felix</tt> in the user's home directory. If
177 * this property is specified, then its value will be used as the cache
178 * directory instead of <tt>.felix</tt>. This directory will be created
179 * if it does not exist.
180 * </li>
181 * <li><tt>felix.cache.profile</tt> - Sets the profile name that will be
182 * used to create a profile directory inside of the cache directory.
183 * The created directory will contained all installed bundles associated
184 * with the profile.
185 * </li>
186 * <li><tt>felix.cache.profiledir</tt> - Sets the directory to use as the
187 * profile directory for the bundle cache; by default the profile
188 * name is used to create a directory in the <tt>.felix</tt> cache
189 * directory. If this property is specified, then the cache directory
190 * and profile name properties are ignored. The specified value of this
191 * property is used directly as the directory to contain all cached
192 * bundles. If this property is set, it is not necessary to set the
193 * cache directory or profile name properties. This directory will be
194 * created if it does not exist.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000195 * </li>
196 * </ul>
197 * <p>
Richard S. Hall930fecc2005-08-16 18:33:34 +0000198 * The <a href="Main.html"><tt>Main</tt></a> class implements some
199 * functionality for default property file handling, which makes it
200 * possible to specify configuration properties and framework properties
201 * in files that are automatically loaded when starting the framework. If you
202 * plan to create your own framework instance, you may be
203 * able to take advantage of the features it provides; refer to its
204 * class documentation for more information.
205 * </p>
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000206 * <p>
207 * The framework is not actually started until the <tt>start()</tt> method
208 * is called.
209 * </p>
Karl Pauls836bb402006-08-24 12:39:46 +0000210 *
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000211 * @param configMap A map for obtaining configuration properties,
Richard S. Hall930fecc2005-08-16 18:33:34 +0000212 * may be <tt>null</tt>.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000213 **/
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000214 public Felix(Map configMap)
Karl Pauls836bb402006-08-24 12:39:46 +0000215 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000216 // Copy the configuration properties; convert keys to strings.
217 m_configMutableMap = new StringMap(false);
218 if (configMap != null)
219 {
220 for (Iterator i = configMap.entrySet().iterator(); i.hasNext(); )
221 {
222 Map.Entry entry = (Map.Entry) i.next();
223 m_configMutableMap.put(entry.getKey().toString(), entry.getValue());
224 }
225 }
Richard S. Hall7adef032007-12-14 21:55:01 +0000226 m_configMap = createUnmodifiableMap(m_configMutableMap);
Richard S. Hall5aa58c62006-12-08 17:08:14 +0000227
228 // Create logger with appropriate log level. Even though the
229 // logger needs the system bundle's context for tracking log
230 // services, it is created now because it is needed before
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000231 // the system bundle is activated. The system bundle's context
232 // will be set in the init() method after the system bundle
233 // is activated.
234 m_logger = (Logger) m_configMutableMap.get(FelixConstants.LOG_LOGGER_PROP);
235 m_logger = (m_logger == null) ? new Logger() : m_logger;
Richard S. Hallc7a576d2007-12-19 22:34:23 +0000236 try
237 {
238 m_logger.setLogLevel(
239 Integer.parseInt(
240 (String) m_configMutableMap.get(FelixConstants.LOG_LEVEL_PROP)));
241 }
242 catch (NumberFormatException ex)
243 {
244 // Ignore and just use the default logging level.
245 }
Richard S. Hall5aa58c62006-12-08 17:08:14 +0000246
Richard S. Hall26b91982007-07-04 21:15:05 +0000247 // Initialize framework properties.
248 initializeFrameworkProperties();
249
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000250 // Create default bundle stream handler.
251 m_bundleStreamHandler = new URLHandlersBundleStreamHandler(this);
252
253 // Create search policy for module loader.
254 m_policyCore = new R4SearchPolicyCore(m_logger, m_configMap);
255
256 // Add a resolver listener to the search policy
257 // so that we will be notified when modules are resolved
258 // in order to update the bundle state.
259 m_policyCore.addResolverListener(new ResolveListener() {
260 public void moduleResolved(ModuleEvent event)
261 {
262 FelixBundle bundle = null;
263 try
264 {
265 long id = Util.getBundleIdFromModuleId(
266 event.getModule().getId());
267 if (id > 0)
268 {
269 // Update the bundle's state to resolved when the
270 // current module is resolved; just ignore resolve
271 // events for older revisions since this only occurs
272 // when an update is done on an unresolved bundle
273 // and there was no refresh performed.
274 bundle = (FelixBundle) getBundle(id);
275
276 // Lock the bundle first.
277 try
278 {
279 acquireBundleLock(bundle);
280 if (bundle.getInfo().getCurrentModule() == event.getModule())
281 {
282 if (bundle.getInfo().getState() != Bundle.INSTALLED)
283 {
284 m_logger.log(
285 Logger.LOG_WARNING,
286 "Received a resolve event for a bundle that has already been resolved.");
287 }
288 else
289 {
290 bundle.getInfo().setState(Bundle.RESOLVED);
291 fireBundleEvent(BundleEvent.RESOLVED, bundle);
292 }
293 }
294 }
295 finally
296 {
297 releaseBundleLock(bundle);
298 }
299 }
300 }
301 catch (NumberFormatException ex)
302 {
303 // Ignore.
304 }
305 }
306
307 public void moduleUnresolved(ModuleEvent event)
308 {
309 // We can ignore this, because the only time it
310 // should happen is when a refresh occurs. The
311 // refresh operation resets the bundle's state
312 // by calling BundleInfo.reset(), thus it is not
313 // necessary for us to reset the bundle's state
314 // here.
315 }
316 });
317
318 // Create the module factory and attach it to the search policy.
319 m_factory = new ModuleFactoryImpl(m_logger);
320 m_policyCore.setModuleFactory(m_factory);
321
322 // Create the system bundle info object, which will hold state info.
Richard S. Halld3cd46c2008-10-10 15:13:10 +0000323 m_sbi = new SystemBundleInfo(m_logger, null);
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000324 // Create the extension manager, which we will use as the module
325 // definition for creating the system bundle module.
326 m_extensionManager = new ExtensionManager(m_logger, m_configMap, m_sbi);
327 m_sbi.addModule(m_factory.createModule("0", m_extensionManager));
328 // Set the extension manager as the content loader for the system
329 // bundle module.
330 m_extensionManager.setSearchPolicy(
331 new R4SearchPolicy(m_policyCore, m_sbi.getCurrentModule()));
332 m_factory.setContentLoader(m_sbi.getCurrentModule(), m_extensionManager);
333 // Lastly, set the system bundle's protection domain.
Richard S. Halle60d8782007-08-17 20:10:27 +0000334 try
335 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000336 addSecurity(this);
Richard S. Halle60d8782007-08-17 20:10:27 +0000337 }
338 catch (Exception ex)
339 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000340 // This should not happen
Richard S. Halle60d8782007-08-17 20:10:27 +0000341 }
Richard S. Hall26b91982007-07-04 21:15:05 +0000342 }
343
Richard S. Hall7adef032007-12-14 21:55:01 +0000344 private Map createUnmodifiableMap(Map mutableMap)
Karl Pauls58248712007-11-06 21:09:10 +0000345 {
346 Map result = Collections.unmodifiableMap(mutableMap);
347
Richard S. Hall7adef032007-12-14 21:55:01 +0000348 // Work around a bug in certain version of J9 where a call to
349 // Collections.unmodifiableMap().keySet().iterator() throws
350 // a NoClassDefFoundError. We try to detect this and return
Karl Pauls58248712007-11-06 21:09:10 +0000351 // the given mutableMap instead.
Richard S. Hall7adef032007-12-14 21:55:01 +0000352 try
Karl Pauls58248712007-11-06 21:09:10 +0000353 {
354 result.keySet().iterator();
355 }
356 catch (NoClassDefFoundError ex)
357 {
358 return mutableMap;
359 }
360
361 return result;
362 }
363
Richard S. Hall26b91982007-07-04 21:15:05 +0000364 //
365 // System Bundle methods.
366 //
367
368 /* package private */ BundleInfo getInfo()
369 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000370 return m_sbi;
Richard S. Hall26b91982007-07-04 21:15:05 +0000371 }
372
373 public BundleContext getBundleContext()
374 {
375// TODO: SECURITY - We need a security check here.
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000376 return m_sbi.getBundleContext();
Richard S. Hall26b91982007-07-04 21:15:05 +0000377 }
378
379 public long getBundleId()
380 {
381 return 0;
382 }
383
384 public URL getEntry(String name)
385 {
386 Object sm = System.getSecurityManager();
387
388 if (sm != null)
389 {
390 try
391 {
392 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
393 AdminPermission.RESOURCE));
394 }
395 catch (Exception e)
396 {
397 return null; // No permission
398 }
399 }
400
401 return getBundleEntry(this, name);
402 }
403
404 public Enumeration getEntryPaths(String path)
405 {
406 Object sm = System.getSecurityManager();
407
408 if (sm != null)
409 {
410 try
411 {
412 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
413 AdminPermission.RESOURCE));
414 }
415 catch (Exception e)
416 {
417 return null; // No permission
418 }
419 }
420
421 return getBundleEntryPaths(this, path);
422 }
423
424 public Enumeration findEntries(String path, String filePattern, boolean recurse)
425 {
426 Object sm = System.getSecurityManager();
427
428 if (sm != null)
429 {
430 try
431 {
432 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
433 AdminPermission.RESOURCE));
434 }
435 catch (Exception e)
436 {
437 return null; // No permission
438 }
439 }
440
441 return findBundleEntries(this, path, filePattern, recurse);
442 }
443
444 public Dictionary getHeaders()
445 {
446 return getHeaders(Locale.getDefault().toString());
447 }
448
449 public Dictionary getHeaders(String locale)
450 {
451 Object sm = System.getSecurityManager();
452
453 if (sm != null)
454 {
455 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
456 AdminPermission.METADATA));
457 }
458 return getBundleHeaders(this, locale);
459 }
460
461 public long getLastModified()
462 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000463 return m_sbi.getLastModified();
Richard S. Hall26b91982007-07-04 21:15:05 +0000464 }
465
466 public String getLocation()
467 {
468 Object sm = System.getSecurityManager();
469
470 if (sm != null)
471 {
472 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
473 AdminPermission.METADATA));
474 }
475 return Constants.SYSTEM_BUNDLE_LOCATION;
476 }
477
478 public URL getResource(String name)
479 {
480 return getBundleResource(this, name);
481 }
482
483 public Enumeration getResources(String name) throws IOException
484 {
485 Object sm = System.getSecurityManager();
486
487 if (sm != null)
488 {
489 try
490 {
491 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
492 AdminPermission.RESOURCE));
493 }
494 catch (Exception e)
495 {
496 return null; // No permission
497 }
498 }
499
500 return getBundleResources(this, name);
501 }
502
503 public ServiceReference[] getRegisteredServices()
504 {
505 Object sm = System.getSecurityManager();
506
507 if (sm != null)
508 {
509 ServiceReference[] refs = getBundleRegisteredServices(this);
510
511 if (refs == null)
512 {
513 return refs;
514 }
515
516 List result = new ArrayList();
517
518 for (int i = 0;i < refs.length;i++)
519 {
520 String[] objectClass = (String[]) refs[i].getProperty(
521 Constants.OBJECTCLASS);
522
523 if (objectClass == null)
524 {
525 continue;
526 }
527
528 for (int j = 0;j < objectClass.length;j++)
529 {
530 try
531 {
532 ((SecurityManager) sm).checkPermission(new ServicePermission(
533 objectClass[j], ServicePermission.GET));
534
535 result.add(refs[i]);
536
537 break;
538 }
539 catch (Exception ex)
540 {
541 // Silently ignore.
542 }
543 }
544 }
545
546 if (result.isEmpty())
547 {
548 return null;
549 }
550
551 return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]);
552 }
553 else
554 {
555 return getBundleRegisteredServices(this);
556 }
557 }
558
559 public ServiceReference[] getServicesInUse()
560 {
561 Object sm = System.getSecurityManager();
562
563 if (sm != null)
564 {
565 ServiceReference[] refs = getBundleServicesInUse(this);
566
567 if (refs == null)
568 {
569 return refs;
570 }
571
572 List result = new ArrayList();
573
574 for (int i = 0;i < refs.length;i++)
575 {
576 String[] objectClass = (String[]) refs[i].getProperty(
577 Constants.OBJECTCLASS);
578
579 if (objectClass == null)
580 {
581 continue;
582 }
583
584 for (int j = 0;j < objectClass.length;j++)
585 {
586 try
587 {
588 ((SecurityManager) sm).checkPermission(new ServicePermission(
589 objectClass[j], ServicePermission.GET));
590
591 result.add(refs[i]);
592
593 break;
594 }
595 catch (Exception e)
596 {
597 // Silently ignore.
598 }
599 }
600 }
601
602 if (result.isEmpty())
603 {
604 return null;
605 }
606
607 return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]);
608 }
609
610 return getBundleServicesInUse(this);
611 }
612
613 public int getState()
614 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000615 return m_sbi.getState();
Richard S. Hall26b91982007-07-04 21:15:05 +0000616 }
617
618 public String getSymbolicName()
619 {
Richard S. Hall9802e3f2008-07-07 01:37:22 +0000620 return Constants.SYSTEM_BUNDLE_SYMBOLICNAME;
Richard S. Hall26b91982007-07-04 21:15:05 +0000621 }
622
623 public boolean hasPermission(Object obj)
624 {
625 return true;
626 }
Richard S. Hall2846a2b2008-06-01 03:08:17 +0000627
Karl Pauls28636dc2008-02-03 21:32:48 +0000628 Object getSignerMatcher()
629 {
630 return null;
631 }
Richard S. Hall26b91982007-07-04 21:15:05 +0000632
633 public Class loadClass(String name) throws ClassNotFoundException
634 {
635 Object sm = System.getSecurityManager();
636
637 if (sm != null)
638 {
639 try
640 {
641 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
642 AdminPermission.CLASS));
643 }
644 catch (Exception e)
645 {
646 throw new ClassNotFoundException("No permission.", e);
647 }
648 }
649
650 return loadBundleClass(this, name);
651 }
652
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000653 /**
654 * This method initializes the framework, which is comprised of resolving
655 * the system bundle, reloading any cached bundles, and activating the system
656 * bundle. The framework is left in the <tt>Bundle.STARTING</tt> state and
657 * reloaded bundles are in the <tt>Bundle.INSTALLED</tt> state. After
658 * successfully invoking this method, <tt>getBundleContext()</tt> will
659 * return a valid <tt>BundleContext</tt> for the system bundle. To finish
660 * starting the framework, invoke the <tt>start()</tt> method.
661 *
662 * @throws org.osgi.framework.BundleException if any error occurs.
663 **/
664 public synchronized void init() throws BundleException
Richard S. Hall26b91982007-07-04 21:15:05 +0000665 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000666 // The system bundle can only be initialized if it currently isn't started.
667 final int state = m_sbi.getState();
668 if ((state == Bundle.INSTALLED) || (state == Bundle.RESOLVED))
Richard S. Hall26b91982007-07-04 21:15:05 +0000669 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000670 // Get any system bundle activators.
671 m_activatorList = (List) m_configMutableMap.get(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP);
672 m_activatorList = (m_activatorList == null) ? new ArrayList() : new ArrayList(m_activatorList);
Richard S. Hall26b91982007-07-04 21:15:05 +0000673
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000674 // Initialize event dispatcher.
675 m_dispatcher = EventDispatcher.start(m_logger);
Richard S. Hall26b91982007-07-04 21:15:05 +0000676
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000677 // Create the bundle cache so that we can reload any installed bundles.
Richard S. Hall930fecc2005-08-16 18:33:34 +0000678 try
679 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000680 m_cache = new BundleCache(m_logger, m_configMap);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000681 }
682 catch (Exception ex)
683 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000684 m_logger.log(Logger.LOG_ERROR, "Error creating bundle cache.", ex);
685 throw new BundleException("Error creating bundle cache.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000686 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000687
Richard S. Hall6bf5ded2008-10-10 15:38:59 +0000688 // If this is the first time init is called, check to see if
689 // we need to flush the bundle cache.
690 if (state == Bundle.INSTALLED)
691 {
692 String flush = (String) m_configMap.get(Constants.FRAMEWORK_STORAGE_CLEAN);
693 if ((flush != null)
694 && flush.equalsIgnoreCase(Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT))
695 {
696 try
697 {
698 m_cache.flush();
699 }
700 catch (Exception ex)
701 {
702 throw new BundleException("Unable to flush bundle cache.", ex);
703 }
704 }
705 }
706
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000707 // Initialize installed bundle data structures.
708 m_installedBundleMap = new HashMap();
709 m_installedBundleIndex = new TreeMap();
Karl Paulsad142d22007-09-16 19:53:22 +0000710
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000711 // Add the system bundle to the set of installed bundles.
712 m_installedBundleMap.put(m_sbi.getLocation(), this);
713 m_installedBundleIndex.put(new Long(0), this);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000714
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000715 // Manually resolve the system bundle, which will cause its
Richard S. Hall7adef032007-12-14 21:55:01 +0000716 // state to be set to RESOLVED.
717 try
718 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000719 m_policyCore.resolve(m_sbi.getCurrentModule());
Richard S. Hall7adef032007-12-14 21:55:01 +0000720 }
721 catch (ResolveException ex)
722 {
723 // This should never happen.
724 throw new BundleException(
Richard S. Hall9802e3f2008-07-07 01:37:22 +0000725 "Unresolved constraint in System Bundle:"
Richard S. Hall7adef032007-12-14 21:55:01 +0000726 + ex.getRequirement());
727 }
Richard S. Hall2846a2b2008-06-01 03:08:17 +0000728
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000729 // Reload the cached bundles before creating and starting the
730 // system bundle, since we want all cached bundles to be reloaded
731 // when we activate the system bundle and any subsequent system
732 // bundle activators passed into the framework constructor.
733 BundleArchive[] archives = null;
Richard S. Hall7adef032007-12-14 21:55:01 +0000734
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000735 // First get cached bundle identifiers.
736 try
Richard S. Halla11f34d2006-10-31 19:39:03 +0000737 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000738 archives = m_cache.getArchives();
Richard S. Halla11f34d2006-10-31 19:39:03 +0000739 }
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000740 catch (Exception ex)
Richard S. Halla11f34d2006-10-31 19:39:03 +0000741 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000742 m_logger.log(Logger.LOG_ERROR, "Unable to list saved bundles.", ex);
743 archives = null;
Richard S. Halla11f34d2006-10-31 19:39:03 +0000744 }
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000745
746 // Now load all cached bundles.
747 for (int i = 0; (archives != null) && (i < archives.length); i++)
748 {
749 try
750 {
751 // Keep track of the max bundle ID currently in use since we
752 // will need to use this as our next bundle ID value if the
753 // persisted value cannot be read.
754 m_nextId = Math.max(m_nextId, archives[i].getId() + 1);
755
756 // It is possible that a bundle in the cache was previously
757 // uninstalled, but not completely deleted (perhaps because
758 // of a crash or a locked file), so if we see an archive
759 // with an UNINSTALLED persistent state, then try to remove
760 // it now.
761 if (archives[i].getPersistentState() == Bundle.UNINSTALLED)
762 {
763 m_cache.remove(archives[i]);
764 }
765 // Otherwise re-install the cached bundle.
766 else
767 {
768 // Install the cached bundle.
769 installBundle(archives[i].getId(), archives[i].getLocation(), null);
770 }
771 }
772 catch (Exception ex)
773 {
774ex.printStackTrace();
775 fireFrameworkEvent(FrameworkEvent.ERROR, this, ex);
776 try
777 {
778 m_logger.log(
779 Logger.LOG_ERROR,
780 "Unable to re-install " + archives[i].getLocation(),
781 ex);
782 }
783 catch (Exception ex2)
784 {
785 m_logger.log(
786 Logger.LOG_ERROR,
787 "Unable to re-install cached bundle.",
788 ex);
789 }
790 // TODO: FRAMEWORK - Perhaps we should remove the cached bundle?
791 }
792 }
793
794 // Now that we have loaded all cached bundles and have determined the
795 // max bundle ID of cached bundles, we need to try to load the next
796 // bundle ID from persistent storage. In case of failure, we should
797 // keep the max value.
798 m_nextId = Math.max(m_nextId, loadNextId());
799
800 // Create service registry.
801 m_registry = new ServiceRegistry(m_logger);
802 // Add a listener to the service registry; this is
803 // used to distribute service registry events to
804 // service listeners.
805 m_registry.addServiceListener(new ServiceListener() {
806 public void serviceChanged(ServiceEvent event)
807 {
808 fireServiceEvent(event);
809 }
810 });
811
812 // The framework is now in its startup sequence.
813 m_sbi.setState(Bundle.STARTING);
814
815 // Now it is possible for threads to wait for the framework to stop,
816 // so create a gate for that purpose.
817 m_shutdownGate = new ThreadGate();
818
819 // Create system bundle activator and bundle context so we can activate it.
820 m_sbi.setActivator(new SystemBundleActivator());
821 m_sbi.setBundleContext(new BundleContextImpl(m_logger, this, this));
822 try
823 {
824 Felix.m_secureAction.startActivator(
825 m_sbi.getActivator(), m_sbi.getBundleContext());
826 }
827 catch (Throwable ex)
828 {
829 m_factory = null;
830 EventDispatcher.shutdown();
831 m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
832 throw new RuntimeException("Unable to start system bundle.");
833 }
834
835 // Now that the system bundle is successfully created we can give
836 // its bundle context to the logger so that it can track log services.
837 m_logger.setSystemBundleContext(m_sbi.getBundleContext());
Richard S. Hall17897152006-03-02 13:43:09 +0000838 }
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000839 }
840
841 /**
842 * This method starts the framework instance, which will transition the
843 * framework from start level 0 to its active start level as specified in
844 * its configuration properties (1 by default). If the <tt>init()</tt> was
845 * not explicitly invoked before calling this method, then it will be
846 * implicitly invoked before starting the framework.
847 *
848 * @throws org.osgi.framework.BundleException if any error occurs.
849 **/
850 public synchronized void start() throws BundleException
851 {
852 final int state = m_sbi.getState();
853 // Initialize if necessary.
854 if ((state == Bundle.INSTALLED) || (state == Bundle.RESOLVED))
Richard S. Hall17897152006-03-02 13:43:09 +0000855 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000856 init();
Richard S. Hall17897152006-03-02 13:43:09 +0000857 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000858
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000859 // If the current state is STARTING, then the system bundle can be started.
860 if (m_sbi.getState() == Bundle.STARTING)
861 {
862 // Get the framework's default start level.
863 int startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
864 String s = (String) m_configMap.get(FelixConstants.FRAMEWORK_STARTLEVEL_PROP);
865 if (s != null)
866 {
867 try
868 {
869 startLevel = Integer.parseInt(s);
870 }
871 catch (NumberFormatException ex)
872 {
873 startLevel = FelixConstants.FRAMEWORK_DEFAULT_STARTLEVEL;
874 }
875 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000876
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000877 // Set the start level using the start level service;
878 // this ensures that all start level requests are
879 // serialized.
880 try
881 {
882 StartLevel sl = (StartLevel) getService(
883 getBundle(0),getServiceReferences((FelixBundle) getBundle(0),
884 StartLevel.class.getName(), null, true)[0]);
885 if (sl instanceof StartLevelImpl)
886 {
887 ((StartLevelImpl) sl).setStartLevelAndWait(startLevel);
888 }
889 else
890 {
891 sl.setStartLevel(startLevel);
892 }
893 }
894 catch (InvalidSyntaxException ex)
895 {
896 // Should never happen.
897 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000898
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000899 // The framework is now running.
900 m_sbi.setState(Bundle.ACTIVE);
901
902 // Fire started event for system bundle.
903 fireBundleEvent(BundleEvent.STARTED, this);
904
905 // Send a framework event to indicate the framework has started.
906 fireFrameworkEvent(FrameworkEvent.STARTED, this, null);
907 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000908 }
909
Richard S. Hall06862742008-09-29 17:37:19 +0000910 public void start(int options) throws BundleException
Richard S. Hall23311f22008-08-01 19:32:10 +0000911 {
Richard S. Hall06862742008-09-29 17:37:19 +0000912 // TODO: FRAMEWORK - For now, ignore all options when starting the
913 // system bundle.
914 start();
Richard S. Hall23311f22008-08-01 19:32:10 +0000915 }
916
Richard S. Hall930fecc2005-08-16 18:33:34 +0000917 /**
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000918 * This method asynchronously shuts down the framework, it must be called at the
Richard S. Hall930fecc2005-08-16 18:33:34 +0000919 * end of a session in order to shutdown all active bundles.
920 **/
Richard S. Hall26b91982007-07-04 21:15:05 +0000921 public void stop() throws BundleException
922 {
923 Object sm = System.getSecurityManager();
924
925 if (sm != null)
926 {
927 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
928 AdminPermission.EXECUTE));
929 }
930
931 stopBundle(this, true);
932 }
933
Richard S. Hall06862742008-09-29 17:37:19 +0000934 public void stop(int options) throws BundleException
Richard S. Hall23311f22008-08-01 19:32:10 +0000935 {
Richard S. Hall06862742008-09-29 17:37:19 +0000936 // TODO: FRAMEWORK - For now, ignore all options when stopping the
937 // system bundle.
938 stop();
Richard S. Hall23311f22008-08-01 19:32:10 +0000939 }
940
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000941 /**
942 * This method will cause the calling thread to block until the framework
943 * shuts down.
944 * @param timeout A timeout value.
945 * @throws java.lang.InterruptedException If the thread was interrupted.
946 **/
Richard S. Hall70855402008-10-10 13:12:44 +0000947 public FrameworkEvent waitForStop(long timeout) throws InterruptedException
Richard S. Hall930fecc2005-08-16 18:33:34 +0000948 {
Richard S. Hall70855402008-10-10 13:12:44 +0000949 // Throw exception if timeout is negative.
950 if (timeout < 0)
951 {
952 throw new IllegalArgumentException("Timeout cannot be negative.");
953 }
954
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000955 // If there is a gate, wait on it; otherwise, return immediately.
956 ThreadGate gate;
Richard S. Hallfe87d662007-05-31 20:07:11 +0000957 synchronized (this)
Richard S. Hall930fecc2005-08-16 18:33:34 +0000958 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000959 gate = m_shutdownGate;
960 }
Richard S. Hall930fecc2005-08-16 18:33:34 +0000961
Richard S. Hallafb4ab42008-10-08 21:18:29 +0000962 if (gate != null)
963 {
964 gate.await(timeout);
Richard S. Hall5eeb1442006-11-07 07:51:24 +0000965 }
Richard S. Hall70855402008-10-10 13:12:44 +0000966
967 // TODO: RFC132 - We need to modify this to return the proper reason:
968 // FrameEvent.STOPPED, FrameEvent.STOPPED_UPDATE,
969 // FrameEvent.STOPPED_BOOTCLASSPATH_MODIFIED, FrameEvent.ERROR
970 return new FrameworkEvent(FrameworkEvent.STOPPED, this, null);
Richard S. Hall5eeb1442006-11-07 07:51:24 +0000971 }
Karl Pauls49400ec2007-02-12 23:49:43 +0000972
Richard S. Hall26b91982007-07-04 21:15:05 +0000973 public void uninstall() throws BundleException
Richard S. Hall5eeb1442006-11-07 07:51:24 +0000974 {
Richard S. Hall26b91982007-07-04 21:15:05 +0000975 throw new BundleException("Cannot uninstall the system bundle.");
Richard S. Halld2d8f9a2007-06-01 13:47:29 +0000976 }
Richard S. Hallfe87d662007-05-31 20:07:11 +0000977
Richard S. Hall26b91982007-07-04 21:15:05 +0000978 public void update() throws BundleException
Richard S. Halld2d8f9a2007-06-01 13:47:29 +0000979 {
Richard S. Hall26b91982007-07-04 21:15:05 +0000980 update(null);
Richard S. Hall930fecc2005-08-16 18:33:34 +0000981 }
982
Richard S. Hall26b91982007-07-04 21:15:05 +0000983 public void update(InputStream is) throws BundleException
Richard S. Hall930fecc2005-08-16 18:33:34 +0000984 {
Richard S. Hall26b91982007-07-04 21:15:05 +0000985 Object sm = System.getSecurityManager();
986
987 if (sm != null)
988 {
989 ((SecurityManager) sm).checkPermission(new AdminPermission(this,
990 AdminPermission.EXECUTE));
991 }
992
993 // TODO: FRAMEWORK - This is supposed to stop and then restart the framework.
994 throw new BundleException("System bundle update not implemented yet.");
995 }
996
997 public String toString()
998 {
999 return getSymbolicName() + " [" + getBundleId() +"]";
Richard S. Hall930fecc2005-08-16 18:33:34 +00001000 }
1001
1002 /**
1003 * Returns the active start level of the framework; this method
1004 * implements functionality for the Start Level service.
1005 * @return The active start level of the framework.
1006 **/
1007 protected int getStartLevel()
1008 {
1009 return m_activeStartLevel;
1010 }
1011
1012 /**
1013 * Implements the functionality of the <tt>setStartLevel()</tt>
1014 * method for the StartLevel service, but does not do the security or
1015 * parameter check. The security and parameter check are done in the
1016 * StartLevel service implementation because this method is called on
1017 * a separate thread and the caller's thread would already be gone if
Richard S. Hall17897152006-03-02 13:43:09 +00001018 * we did the checks in this method. This method should not be called
1019 * directly.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001020 * @param requestedLevel The new start level of the framework.
1021 **/
Richard S. Hall441c7152006-02-17 11:07:10 +00001022 protected void setFrameworkStartLevel(int requestedLevel)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001023 {
Richard S. Hall17897152006-03-02 13:43:09 +00001024 Bundle[] bundles = null;
1025
1026 // Synchronization for changing the start level is rather loose.
1027 // The install lock is grabbed initially to atomically change the
1028 // framework's start level and to grab a sorted snapshot of the
1029 // currently installed bundles, but then this lock is freed immediately.
1030 // No locks are held while processing the currently installed bundles
1031 // for starting/stopping based on the new start level. The only locking
1032 // that occurs is for individual bundles when startBundle()/stopBundle()
1033 // is called, but this locking is done in the respective method.
1034 //
1035 // This approach does mean that it is possible for a for individual
1036 // bundle states to change during this operation. For example, bundle
1037 // start levels can be changed or bundles can be uninstalled. If a
1038 // bundle's start level changes, then it is possible for it to be
1039 // processed out of order. Uninstalled bundles are just logged and
1040 // ignored. I had a bit of discussion with Peter Kriens about these
1041 // issues and he felt they were consistent with the spec, which
1042 // intended Start Level to have some leeway.
1043 //
1044 // Calls to this method are only made by the start level thread, which
1045 // serializes framework start level changes. Thus, it is not possible
1046 // for two requests to change the framework's start level to interfere
1047 // with each other.
1048
1049 synchronized (m_installedBundleLock_Priority2)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001050 {
Richard S. Hall17897152006-03-02 13:43:09 +00001051 // Determine if we are lowering or raising the
1052 // active start level.
1053 boolean lowering = (requestedLevel < m_activeStartLevel);
Karl Pauls836bb402006-08-24 12:39:46 +00001054
Richard S. Hall17897152006-03-02 13:43:09 +00001055 // Record new start level.
1056 m_activeStartLevel = requestedLevel;
Karl Pauls836bb402006-08-24 12:39:46 +00001057
Richard S. Hall17897152006-03-02 13:43:09 +00001058 // Get a snapshot of all installed bundles.
1059 bundles = getBundles();
1060
1061 // Sort bundle array by start level either ascending or
1062 // descending depending on whether the start level is being
1063 // lowered or raised to that the bundles can be efficiently
Richard S. Hall5259e3e2006-07-14 18:55:59 +00001064 // processed in order. Within a start level sort by bundle ID.
Richard S. Hall17897152006-03-02 13:43:09 +00001065 Comparator comparator = null;
1066 if (lowering)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001067 {
Richard S. Hall17897152006-03-02 13:43:09 +00001068 // Sort descending to stop highest start level first.
1069 comparator = new Comparator() {
1070 public int compare(Object o1, Object o2)
Richard S. Hall441c7152006-02-17 11:07:10 +00001071 {
Richard S. Hall26b91982007-07-04 21:15:05 +00001072 FelixBundle b1 = (FelixBundle) o1;
1073 FelixBundle b2 = (FelixBundle) o2;
Richard S. Hall17897152006-03-02 13:43:09 +00001074 if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
1075 < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
1076 {
1077 return 1;
1078 }
1079 else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
1080 > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
1081 {
1082 return -1;
1083 }
Karl Paulsa7e36b82008-04-13 19:09:20 +00001084 else if (b1.getBundleId() < b2.getBundleId())
Richard S. Hall5259e3e2006-07-14 18:55:59 +00001085 {
1086 return 1;
1087 }
1088 return -1;
Richard S. Hall441c7152006-02-17 11:07:10 +00001089 }
Richard S. Hall17897152006-03-02 13:43:09 +00001090 };
1091 }
1092 else
1093 {
1094 // Sort ascending to start lowest start level first.
1095 comparator = new Comparator() {
1096 public int compare(Object o1, Object o2)
Richard S. Hall441c7152006-02-17 11:07:10 +00001097 {
Richard S. Hall26b91982007-07-04 21:15:05 +00001098 FelixBundle b1 = (FelixBundle) o1;
1099 FelixBundle b2 = (FelixBundle) o2;
Richard S. Hall17897152006-03-02 13:43:09 +00001100 if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
1101 > b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
Richard S. Hall441c7152006-02-17 11:07:10 +00001102 {
Richard S. Hall17897152006-03-02 13:43:09 +00001103 return 1;
Richard S. Hall441c7152006-02-17 11:07:10 +00001104 }
Richard S. Hall17897152006-03-02 13:43:09 +00001105 else if (b1.getInfo().getStartLevel(getInitialBundleStartLevel())
1106 < b2.getInfo().getStartLevel(getInitialBundleStartLevel()))
Richard S. Hall441c7152006-02-17 11:07:10 +00001107 {
Richard S. Hall17897152006-03-02 13:43:09 +00001108 return -1;
Richard S. Hall441c7152006-02-17 11:07:10 +00001109 }
Karl Paulsa7e36b82008-04-13 19:09:20 +00001110 else if (b1.getBundleId() > b2.getBundleId())
Richard S. Hall5259e3e2006-07-14 18:55:59 +00001111 {
1112 return 1;
1113 }
1114 return -1;
Richard S. Hall17897152006-03-02 13:43:09 +00001115 }
1116 };
1117 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001118
Richard S. Hall17897152006-03-02 13:43:09 +00001119 Arrays.sort(bundles, comparator);
1120 }
1121
1122 // Stop or start the bundles according to the start level.
1123 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
1124 {
Richard S. Hall26b91982007-07-04 21:15:05 +00001125 FelixBundle impl = (FelixBundle) bundles[i];
Richard S. Hall17897152006-03-02 13:43:09 +00001126
1127 // Ignore the system bundle, since its start() and
1128 // stop() methods get called explicitly in Felix.start()
1129 // and Felix.shutdown(), respectively.
1130 if (impl.getInfo().getBundleId() == 0)
1131 {
1132 continue;
1133 }
1134
1135 // Lock the current bundle.
1136 acquireBundleLock(impl);
1137
1138 try
1139 {
1140 // Start the bundle if necessary.
1141 if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
1142 (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
1143 <= m_activeStartLevel))
1144 {
1145 try
1146 {
1147 startBundle(impl, false);
1148 }
1149 catch (Throwable th)
1150 {
1151 fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
1152 m_logger.log(
1153 Logger.LOG_ERROR,
1154 "Error starting " + impl.getInfo().getLocation(), th);
Richard S. Hall441c7152006-02-17 11:07:10 +00001155 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001156 }
Richard S. Hall17897152006-03-02 13:43:09 +00001157 // Stop the bundle if necessary.
1158 else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
1159 > m_activeStartLevel)
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001160 {
Richard S. Hall17897152006-03-02 13:43:09 +00001161 try
Richard S. Hall441c7152006-02-17 11:07:10 +00001162 {
Richard S. Hall17897152006-03-02 13:43:09 +00001163 stopBundle(impl, false);
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001164 }
Richard S. Hall17897152006-03-02 13:43:09 +00001165 catch (Throwable th)
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001166 {
Richard S. Hall17897152006-03-02 13:43:09 +00001167 fireFrameworkEvent(FrameworkEvent.ERROR, impl, th);
1168 m_logger.log(
1169 Logger.LOG_ERROR,
1170 "Error stopping " + impl.getInfo().getLocation(), th);
Richard S. Hall441c7152006-02-17 11:07:10 +00001171 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001172 }
Richard S. Hall17897152006-03-02 13:43:09 +00001173 }
1174 finally
1175 {
1176 // Always release bundle lock.
1177 releaseBundleLock(impl);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001178 }
Richard S. Hall9b2a3292008-03-01 23:49:01 +00001179 // Hint to GC to collect bundle; not sure why this
1180 // is necessary, but it appears to help.
1181 bundles[i] = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001182 }
1183
Richard S. Hallafb4ab42008-10-08 21:18:29 +00001184 if (m_sbi.getState() == Bundle.ACTIVE)
Richard S. Halla11f34d2006-10-31 19:39:03 +00001185 {
Richard S. Hallfaa3d612007-10-24 14:18:17 +00001186 fireFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, this, null);
Richard S. Halla11f34d2006-10-31 19:39:03 +00001187 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001188 }
1189
1190 /**
1191 * Returns the start level into which newly installed bundles will
1192 * be placed by default; this method implements functionality for
1193 * the Start Level service.
1194 * @return The default start level for newly installed bundles.
1195 **/
1196 protected int getInitialBundleStartLevel()
1197 {
Richard S. Hall471e3e62007-07-11 19:25:33 +00001198 String s = (String) m_configMap.get(FelixConstants.BUNDLE_STARTLEVEL_PROP);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001199
1200 if (s != null)
1201 {
1202 try
1203 {
1204 int i = Integer.parseInt(s);
1205 return (i > 0) ? i : FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
1206 }
1207 catch (NumberFormatException ex)
1208 {
1209 // Ignore and return the default value.
1210 }
1211 }
1212 return FelixConstants.BUNDLE_DEFAULT_STARTLEVEL;
1213 }
1214
1215 /**
1216 * Sets the default start level into which newly installed bundles
1217 * will be placed; this method implements functionality for the Start
1218 * Level service.
1219 * @param startLevel The new default start level for newly installed
1220 * bundles.
1221 * @throws java.lang.IllegalArgumentException If the specified start
1222 * level is not greater than zero.
1223 * @throws java.security.SecurityException If the caller does not
1224 * have <tt>AdminPermission</tt>.
1225 **/
1226 protected void setInitialBundleStartLevel(int startLevel)
1227 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001228 if (startLevel <= 0)
1229 {
1230 throw new IllegalArgumentException(
1231 "Initial start level must be greater than zero.");
1232 }
1233
Richard S. Hall471e3e62007-07-11 19:25:33 +00001234 m_configMutableMap.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00001235 FelixConstants.BUNDLE_STARTLEVEL_PROP, Integer.toString(startLevel));
1236 }
1237
1238 /**
1239 * Returns the start level for the specified bundle; this method
1240 * implements functionality for the Start Level service.
1241 * @param bundle The bundle to examine.
1242 * @return The start level of the specified bundle.
1243 * @throws java.lang.IllegalArgumentException If the specified
1244 * bundle has been uninstalled.
1245 **/
1246 protected int getBundleStartLevel(Bundle bundle)
1247 {
1248 if (bundle.getState() == Bundle.UNINSTALLED)
1249 {
1250 throw new IllegalArgumentException("Bundle is uninstalled.");
1251 }
1252
Richard S. Hall26b91982007-07-04 21:15:05 +00001253 return ((FelixBundle) bundle).getInfo().getStartLevel(getInitialBundleStartLevel());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001254 }
1255
1256 /**
1257 * Sets the start level of the specified bundle; this method
1258 * implements functionality for the Start Level service.
1259 * @param bundle The bundle whose start level is to be modified.
1260 * @param startLevel The new start level of the specified bundle.
1261 * @throws java.lang.IllegalArgumentException If the specified
1262 * bundle is the system bundle or if the bundle has been
1263 * uninstalled.
1264 * @throws java.security.SecurityException If the caller does not
1265 * have <tt>AdminPermission</tt>.
1266 **/
1267 protected void setBundleStartLevel(Bundle bundle, int startLevel)
1268 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001269 // Acquire bundle lock.
Richard S. Hall26b91982007-07-04 21:15:05 +00001270 acquireBundleLock((FelixBundle) bundle);
Karl Pauls836bb402006-08-24 12:39:46 +00001271
Richard S. Hall930fecc2005-08-16 18:33:34 +00001272 Throwable rethrow = null;
1273
1274 try
1275 {
1276 if (bundle.getState() == Bundle.UNINSTALLED)
1277 {
1278 throw new IllegalArgumentException("Bundle is uninstalled.");
1279 }
1280
1281 if (startLevel >= 1)
1282 {
Richard S. Hall26b91982007-07-04 21:15:05 +00001283 FelixBundle impl = (FelixBundle) bundle;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001284 impl.getInfo().setStartLevel(startLevel);
Karl Pauls836bb402006-08-24 12:39:46 +00001285
Richard S. Hall930fecc2005-08-16 18:33:34 +00001286 try
1287 {
1288 // Start the bundle if necessary.
1289 if ((impl.getInfo().getPersistentState() == Bundle.ACTIVE) &&
1290 (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
1291 <= m_activeStartLevel))
1292 {
1293 startBundle(impl, false);
1294 }
1295 // Stop the bundle if necessary.
1296 else if (impl.getInfo().getStartLevel(getInitialBundleStartLevel())
1297 > m_activeStartLevel)
1298 {
1299 stopBundle(impl, false);
1300 }
1301 }
1302 catch (Throwable th)
1303 {
1304 rethrow = th;
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001305 m_logger.log(Logger.LOG_ERROR, "Error starting/stopping bundle.", th);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001306 }
1307 }
1308 else
1309 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001310 m_logger.log(Logger.LOG_WARNING, "Bundle start level must be greater than zero.");
Richard S. Hall930fecc2005-08-16 18:33:34 +00001311 }
1312 }
1313 finally
1314 {
1315 // Always release bundle lock.
Richard S. Hall26b91982007-07-04 21:15:05 +00001316 releaseBundleLock((FelixBundle) bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001317 }
1318
1319 if (rethrow != null)
1320 {
1321 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, rethrow);
1322 }
1323 }
1324
1325 /**
1326 * Returns whether a bundle is persistently started; this is an
1327 * method implementation for the Start Level service.
1328 * @param bundle The bundle to examine.
1329 * @return <tt>true</tt> if the bundle is marked as persistently
1330 * started, <tt>false</tt> otherwise.
1331 * @throws java.lang.IllegalArgumentException If the specified
1332 * bundle has been uninstalled.
1333 **/
1334 protected boolean isBundlePersistentlyStarted(Bundle bundle)
1335 {
1336 if (bundle.getState() == Bundle.UNINSTALLED)
1337 {
1338 throw new IllegalArgumentException("Bundle is uninstalled.");
1339 }
1340
Richard S. Hall26b91982007-07-04 21:15:05 +00001341 return (((FelixBundle) bundle).getInfo().getPersistentState() == Bundle.ACTIVE);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001342 }
1343
1344 //
1345 // Implementation of Bundle interface methods.
1346 //
1347
1348 /**
Richard S. Hall05fd75e2007-01-18 01:36:45 +00001349 * Get bundle headers and resolve any localized strings from resource bundles.
1350 * @param bundle
1351 * @param locale
1352 * @return localized bundle headers dictionary.
1353 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00001354 protected Dictionary getBundleHeaders(FelixBundle bundle, String locale)
Richard S. Hall05fd75e2007-01-18 01:36:45 +00001355 {
1356 return new MapToDictionary(bundle.getInfo().getCurrentLocalizedHeader(locale));
Richard S. Hall930fecc2005-08-16 18:33:34 +00001357 }
1358
1359 /**
1360 * Implementation for Bundle.getLocation().
1361 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00001362 protected String getBundleLocation(FelixBundle bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001363 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001364 return bundle.getInfo().getLocation();
1365 }
1366
1367 /**
1368 * Implementation for Bundle.getResource().
1369 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00001370 protected URL getBundleResource(FelixBundle bundle, String name)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001371 {
1372 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1373 {
1374 throw new IllegalStateException("The bundle is uninstalled.");
1375 }
Richard S. Hall001cc302006-02-03 15:03:24 +00001376 return bundle.getInfo().getCurrentModule().getResource(name);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001377 }
1378
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001379 /**
Richard S. Hall864dc662006-09-26 16:53:29 +00001380 * Implementation for Bundle.getResources().
1381 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00001382 protected Enumeration getBundleResources(FelixBundle bundle, String name)
Richard S. Hall864dc662006-09-26 16:53:29 +00001383 {
1384 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1385 {
1386 throw new IllegalStateException("The bundle is uninstalled.");
1387 }
1388 return bundle.getInfo().getCurrentModule().getResources(name);
1389 }
1390
1391 /**
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001392 * Implementation for Bundle.getEntry().
1393 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00001394 protected URL getBundleEntry(FelixBundle bundle, String name)
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001395 {
1396 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1397 {
1398 throw new IllegalStateException("The bundle is uninstalled.");
1399 }
Richard S. Hall8d861e52006-09-25 18:29:27 +00001400 return bundle.getInfo().getCurrentModule()
1401 .getContentLoader().getResourceFromContent(name);
Richard S. Hallbcbf83e2006-02-05 13:28:26 +00001402 }
1403
Richard S. Hall4f09b642006-02-06 10:59:19 +00001404 /**
1405 * Implementation for Bundle.getEntryPaths().
1406 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00001407 protected Enumeration getBundleEntryPaths(FelixBundle bundle, String path)
Richard S. Hall4f09b642006-02-06 10:59:19 +00001408 {
1409 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1410 {
1411 throw new IllegalStateException("The bundle is uninstalled.");
1412 }
Richard S. Hall6fa05d02006-07-21 08:24:12 +00001413
1414 // Get the entry enumeration from the module content and
1415 // create a wrapper enumeration to filter it.
1416 Enumeration enumeration = new GetEntryPathsEnumeration(bundle, path);
1417
1418 // Return the enumeration if it has elements.
1419 return (!enumeration.hasMoreElements()) ? null : enumeration;
Richard S. Hall4f09b642006-02-06 10:59:19 +00001420 }
1421
Richard S. Hall4d2f3972006-07-20 15:58:17 +00001422 /**
1423 * Implementation for findEntries().
1424 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00001425 protected Enumeration findBundleEntries(
1426 FelixBundle bundle, String path, String filePattern, boolean recurse)
Richard S. Hall4d2f3972006-07-20 15:58:17 +00001427 {
Richard S. Hall4d2f3972006-07-20 15:58:17 +00001428 // Try to resolve the bundle per the spec.
1429 resolveBundles(new Bundle[] { bundle });
1430
Richard S. Hall6fa05d02006-07-21 08:24:12 +00001431 // Get the entry enumeration from the module content and
1432 // create a wrapper enumeration to filter it.
1433 Enumeration enumeration =
1434 new FindEntriesEnumeration(bundle, path, filePattern, recurse);
Richard S. Hall4d2f3972006-07-20 15:58:17 +00001435
Richard S. Hall6fa05d02006-07-21 08:24:12 +00001436 // Return the enumeration if it has elements.
1437 return (!enumeration.hasMoreElements()) ? null : enumeration;
Richard S. Hall4d2f3972006-07-20 15:58:17 +00001438 }
1439
Richard S. Hall26b91982007-07-04 21:15:05 +00001440 protected ServiceReference[] getBundleRegisteredServices(FelixBundle bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001441 {
1442 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1443 {
1444 throw new IllegalStateException("The bundle is uninstalled.");
1445 }
1446
1447 // Filter list of registered service references.
1448 ServiceReference[] refs = m_registry.getRegisteredServices(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001449
Karl Paulsc19abb42006-07-21 10:23:11 +00001450 return refs;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001451 }
1452
1453 protected ServiceReference[] getBundleServicesInUse(Bundle bundle)
1454 {
1455 // Filter list of "in use" service references.
1456 ServiceReference[] refs = m_registry.getServicesInUse(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001457
Karl Paulsc19abb42006-07-21 10:23:11 +00001458 return refs;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001459 }
1460
Richard S. Hall26b91982007-07-04 21:15:05 +00001461 protected boolean bundleHasPermission(FelixBundle bundle, Object obj)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001462 {
1463 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1464 {
1465 throw new IllegalStateException("The bundle is uninstalled.");
1466 }
1467
Richard S. Hall2cf44c92006-01-23 19:23:56 +00001468 if (System.getSecurityManager() != null)
Richard S. Hall65730962006-01-23 19:23:13 +00001469 {
1470 try
1471 {
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001472 return (obj instanceof java.security.Permission)
Karl Pauls28636dc2008-02-03 21:32:48 +00001473 ? impliesBundlePermission(
Richard S. Hall2846a2b2008-06-01 03:08:17 +00001474 (BundleProtectionDomain)
1475 bundle.getInfo().getProtectionDomain(),
Karl Pauls28636dc2008-02-03 21:32:48 +00001476 (java.security.Permission) obj, true)
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001477 : false;
Richard S. Hall65730962006-01-23 19:23:13 +00001478 }
1479 catch (Exception ex)
1480 {
1481 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001482 Logger.LOG_WARNING,
Richard S. Hall65730962006-01-23 19:23:13 +00001483 "Exception while evaluating the permission.",
1484 ex);
Karl Pauls836bb402006-08-24 12:39:46 +00001485 return false;
Richard S. Hall65730962006-01-23 19:23:13 +00001486 }
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001487 }
Richard S. Hall65730962006-01-23 19:23:13 +00001488
Richard S. Halld1e3cbd2006-01-27 15:23:01 +00001489 return true;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001490 }
1491
1492 /**
Richard S. Hall74b97972005-11-30 15:51:41 +00001493 * Implementation for Bundle.loadClass().
1494 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00001495 protected Class loadBundleClass(FelixBundle bundle, String name) throws ClassNotFoundException
Richard S. Hall74b97972005-11-30 15:51:41 +00001496 {
Richard S. Hall044cda82007-12-20 19:14:25 +00001497 if (bundle.getInfo().getState() == Bundle.UNINSTALLED)
1498 {
1499 throw new IllegalStateException("Bundle is uninstalled");
1500 }
1501 else if (bundle.getInfo().getState() == Bundle.INSTALLED)
1502 {
1503 try
1504 {
1505 _resolveBundle(bundle);
1506 }
1507 catch (BundleException ex)
1508 {
1509 // The spec says we must fire a framework error.
1510 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
1511 // Then throw a class not found exception.
1512 throw new ClassNotFoundException(name);
1513 }
1514 }
Karl Paulsb6ad9922008-08-20 16:37:33 +00001515 return bundle.getInfo().getCurrentModule().getClass(name);
Richard S. Hall74b97972005-11-30 15:51:41 +00001516 }
1517
1518 /**
Richard S. Hall930fecc2005-08-16 18:33:34 +00001519 * Implementation for Bundle.start().
1520 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00001521 protected void startBundle(FelixBundle bundle, boolean record)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001522 throws BundleException
1523 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001524 // CONCURRENCY NOTE:
1525 // Starting a bundle may actually impact many bundles, since
1526 // the bundle being started my need to be resolved, which in
1527 // turn may need to resolve other bundles. Despite this fact,
1528 // we only acquire the lock for the bundle being started, because
1529 // when resolve is called on this bundle, it will eventually
1530 // call resolve on the module loader search policy, which does
Karl Pauls836bb402006-08-24 12:39:46 +00001531 // its own locking on the module factory instance. Since the
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001532 // resolve algorithm is locking the module factory instance, it
Richard S. Hall930fecc2005-08-16 18:33:34 +00001533 // is not possible for other bundles to be installed or removed,
1534 // so we don't have to worry about these possibilities.
1535 //
1536 // Further, if other bundles are started during this operation,
1537 // then either they will resolve first because they got the lock
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001538 // on the module factory or we will resolve first since we got
1539 // the lock on the module factory, so there should be no interference.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001540 // If other bundles are stopped or uninstalled, this should pose
1541 // no problems, since this does not impact their resolved state.
1542 // If a refresh occurs, then the refresh algorithm ulimately has
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001543 // to acquire the module factory instance lock too before it can
Richard S. Hall930fecc2005-08-16 18:33:34 +00001544 // completely purge old modules, so it should also complete either
1545 // before or after this bundle is started. At least that's the
1546 // theory.
1547
1548 // Acquire bundle lock.
1549 acquireBundleLock(bundle);
1550
1551 try
1552 {
1553 _startBundle(bundle, record);
1554 }
1555 finally
1556 {
1557 // Release bundle lock.
1558 releaseBundleLock(bundle);
1559 }
1560 }
1561
Richard S. Hall26b91982007-07-04 21:15:05 +00001562 private void _startBundle(FelixBundle bundle, boolean record)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001563 throws BundleException
1564 {
Richard S. Hall06862742008-09-29 17:37:19 +00001565 // Get bundle info object.
1566 BundleInfo info = bundle.getInfo();
1567
Karl Pauls49400ec2007-02-12 23:49:43 +00001568 // The spec doesn't say whether it is possible to start an extension
1569 // We just do nothing
Richard S. Hall06862742008-09-29 17:37:19 +00001570 if (info.isExtension())
Karl Pauls49400ec2007-02-12 23:49:43 +00001571 {
1572 return;
1573 }
1574
Richard S. Hall930fecc2005-08-16 18:33:34 +00001575 // Set and save the bundle's persistent state to active
1576 // if we are supposed to record state change.
1577 if (record)
1578 {
Richard S. Hall06862742008-09-29 17:37:19 +00001579 info.setPersistentStateActive();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001580 }
1581
Richard S. Hall06862742008-09-29 17:37:19 +00001582 // Check to see if the bundle's start level is greater than the
1583 // the framework's start level.
1584 if (info.getStartLevel(getInitialBundleStartLevel()) > getStartLevel())
Richard S. Hall930fecc2005-08-16 18:33:34 +00001585 {
Richard S. Hall06862742008-09-29 17:37:19 +00001586 // Throw an exception for transient starts.
1587 if (!record)
1588 {
1589 throw new BundleException(
Richard S. Hall12bbff62008-10-10 14:30:42 +00001590 "Cannot start bundle " + bundle + " because its start level is "
Richard S. Hall06862742008-09-29 17:37:19 +00001591 + info.getStartLevel(getInitialBundleStartLevel())
1592 + ", which is greater than the framework's start level of "
1593 + getStartLevel() + ".");
1594 }
1595 // Ignore persistent starts.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001596 return;
1597 }
1598
1599 switch (info.getState())
1600 {
1601 case Bundle.UNINSTALLED:
1602 throw new IllegalStateException("Cannot start an uninstalled bundle.");
1603 case Bundle.STARTING:
1604 case Bundle.STOPPING:
Richard S. Hall12bbff62008-10-10 14:30:42 +00001605 throw new BundleException(
1606 "Bundle " + bundle + " cannot be started, since it is either starting or stopping.");
Richard S. Hall930fecc2005-08-16 18:33:34 +00001607 case Bundle.ACTIVE:
1608 return;
1609 case Bundle.INSTALLED:
1610 _resolveBundle(bundle);
Richard S. Halle50da252006-07-25 07:48:06 +00001611 // No break.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001612 case Bundle.RESOLVED:
1613 info.setState(Bundle.STARTING);
Richard S. Halle50da252006-07-25 07:48:06 +00001614 fireBundleEvent(BundleEvent.STARTING, bundle);
1615 break;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001616 }
1617
1618 try
1619 {
Richard S. Hall2a28c8d2006-07-25 07:50:41 +00001620 // Set the bundle's context.
Richard S. Hall26b91982007-07-04 21:15:05 +00001621 info.setBundleContext(new BundleContextImpl(m_logger, this, bundle));
Richard S. Hall2a28c8d2006-07-25 07:50:41 +00001622
Richard S. Hall930fecc2005-08-16 18:33:34 +00001623 // Set the bundle's activator.
Richard S. Halle50da252006-07-25 07:48:06 +00001624 info.setActivator(createBundleActivator(bundle.getInfo()));
Richard S. Hall930fecc2005-08-16 18:33:34 +00001625
1626 // Activate the bundle if it has an activator.
1627 if (bundle.getInfo().getActivator() != null)
1628 {
Richard S. Hallfe87d662007-05-31 20:07:11 +00001629 m_secureAction.startActivator(info.getActivator(),info.getBundleContext());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001630 }
1631
Richard S. Hall3c26cc02006-02-17 13:51:21 +00001632 // TODO: CONCURRENCY - Reconsider firing event outside of the
1633 // bundle lock.
Richard S. Halle50da252006-07-25 07:48:06 +00001634 info.setState(Bundle.ACTIVE);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001635 fireBundleEvent(BundleEvent.STARTED, bundle);
1636 }
1637 catch (Throwable th)
1638 {
1639 // If there was an error starting the bundle,
1640 // then reset its state to RESOLVED.
1641 info.setState(Bundle.RESOLVED);
1642
Richard S. Hall2a28c8d2006-07-25 07:50:41 +00001643 // Clean up the bundle context.
Richard S. Hallfe87d662007-05-31 20:07:11 +00001644 ((BundleContextImpl) info.getBundleContext()).invalidate();
1645 info.setBundleContext(null);
Richard S. Hall187b87a2006-07-03 09:13:18 +00001646
Karl Paulscc12bd92008-10-10 21:32:52 +00001647 // Clean up the bundle activator
1648 info.setActivator(null);
1649
Richard S. Hall930fecc2005-08-16 18:33:34 +00001650 // Unregister any services offered by this bundle.
1651 m_registry.unregisterServices(bundle);
1652
1653 // Release any services being used by this bundle.
1654 m_registry.ungetServices(bundle);
1655
1656 // Remove any listeners registered by this bundle.
Richard S. Hall92770632006-07-24 10:18:52 +00001657 m_dispatcher.removeListeners(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001658
1659 // The spec says to expect BundleException or
1660 // SecurityException, so rethrow these exceptions.
1661 if (th instanceof BundleException)
1662 {
1663 throw (BundleException) th;
1664 }
1665 else if (th instanceof SecurityException)
1666 {
1667 throw (SecurityException) th;
1668 }
Karl Pauls836bb402006-08-24 12:39:46 +00001669 else if ((System.getSecurityManager() != null) &&
Karl Paulsc19abb42006-07-21 10:23:11 +00001670 (th instanceof java.security.PrivilegedActionException))
Richard S. Hall930fecc2005-08-16 18:33:34 +00001671 {
Karl Paulsc19abb42006-07-21 10:23:11 +00001672 th = ((java.security.PrivilegedActionException) th).getException();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001673 }
1674
1675 // Rethrow all other exceptions as a BundleException.
Richard S. Hall12bbff62008-10-10 14:30:42 +00001676 throw new BundleException("Activator start error in bundle " + bundle + ".", th);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001677 }
1678 }
1679
Richard S. Hall26b91982007-07-04 21:15:05 +00001680 protected void _resolveBundle(FelixBundle bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001681 throws BundleException
1682 {
Karl Paulsebce0842008-03-19 17:35:58 +00001683 if (bundle.getInfo().isExtension())
1684 {
1685 return;
1686 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001687 // If a security manager is installed, then check for permission
1688 // to import the necessary packages.
1689 if (System.getSecurityManager() != null)
1690 {
Richard S. Hall2846a2b2008-06-01 03:08:17 +00001691 BundleProtectionDomain pd = (BundleProtectionDomain)
Karl Pauls758c2be2008-03-05 13:10:04 +00001692 bundle.getInfo().getProtectionDomain();
Karl Pauls836bb402006-08-24 12:39:46 +00001693
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001694 IRequirement[] imports =
1695 bundle.getInfo().getCurrentModule().getDefinition().getRequirements();
Karl Pauls836bb402006-08-24 12:39:46 +00001696
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001697/*
1698 TODO: RB - We need to fix this import check by looking at the wire
1699 associated with it, not the import since we don't know the
1700 package name associated with the import since it is a filter.
1701
1702 for (int i = 0; i < imports.length; i++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001703 {
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001704 if (imports[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
Karl Paulsc19abb42006-07-21 10:23:11 +00001705 {
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001706 PackagePermission perm = new PackagePermission(
1707 imports[i].???,
1708 PackagePermission.IMPORT);
Karl Pauls49400ec2007-02-12 23:49:43 +00001709
Karl Pauls758c2be2008-03-05 13:10:04 +00001710 if (!pd.impliesDirect(perm))
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001711 {
1712 throw new java.security.AccessControlException(
1713 "PackagePermission.IMPORT denied for import: " +
1714 imports[i].getName(), perm);
1715 }
Karl Paulsc19abb42006-07-21 10:23:11 +00001716 }
Karl Pauls836bb402006-08-24 12:39:46 +00001717 }
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001718*/
Karl Pauls836bb402006-08-24 12:39:46 +00001719 // Check export permission for all exports of the current module.
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001720 ICapability[] exports =
1721 bundle.getInfo().getCurrentModule().getDefinition().getCapabilities();
1722 for (int i = 0; i < exports.length; i++)
Karl Pauls836bb402006-08-24 12:39:46 +00001723 {
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001724 if (exports[i].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
Karl Paulsc19abb42006-07-21 10:23:11 +00001725 {
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001726 PackagePermission perm = new PackagePermission(
1727 (String) exports[i].getProperties().get(ICapability.PACKAGE_PROPERTY), PackagePermission.EXPORT);
Karl Pauls49400ec2007-02-12 23:49:43 +00001728
Karl Pauls758c2be2008-03-05 13:10:04 +00001729 if (!pd.impliesDirect(perm))
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001730 {
1731 throw new java.security.AccessControlException(
1732 "PackagePermission.EXPORT denied for export: " +
1733 exports[i].getProperties().get(ICapability.PACKAGE_PROPERTY), perm);
1734 }
Karl Paulsc19abb42006-07-21 10:23:11 +00001735 }
1736 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001737 }
1738
Richard S. Hall9955e902007-01-25 14:42:01 +00001739 verifyExecutionEnvironment(bundle);
Karl Pauls49400ec2007-02-12 23:49:43 +00001740
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001741 IModule module = bundle.getInfo().getCurrentModule();
Richard S. Hall930fecc2005-08-16 18:33:34 +00001742 try
1743 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001744 m_policyCore.resolve(module);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001745 }
1746 catch (ResolveException ex)
1747 {
1748 if (ex.getModule() != null)
1749 {
1750 throw new BundleException(
Richard S. Hall9802e3f2008-07-07 01:37:22 +00001751 "Unresolved constraint in bundle "
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001752 + Util.getBundleIdFromModuleId(ex.getModule().getId())
Richard S. Hallbf12bf72007-01-22 07:15:25 +00001753 + ": " + ex.getRequirement());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001754 }
1755 else
1756 {
1757 throw new BundleException(ex.getMessage());
1758 }
1759 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001760 }
1761
Richard S. Hall26b91982007-07-04 21:15:05 +00001762 protected void updateBundle(FelixBundle bundle, InputStream is)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001763 throws BundleException
1764 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001765 // Acquire bundle lock.
1766 acquireBundleLock(bundle);
1767
1768 try
1769 {
1770 _updateBundle(bundle, is);
1771 }
1772 finally
1773 {
1774 // Release bundle lock.
1775 releaseBundleLock(bundle);
1776 }
1777 }
1778
Richard S. Hall26b91982007-07-04 21:15:05 +00001779 protected void _updateBundle(FelixBundle bundle, InputStream is)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001780 throws BundleException
1781 {
1782 // We guarantee to close the input stream, so put it in a
1783 // finally clause.
Karl Pauls836bb402006-08-24 12:39:46 +00001784
Richard S. Hall930fecc2005-08-16 18:33:34 +00001785 try
1786 {
1787 // Variable to indicate whether bundle is active or not.
Karl Pauls49400ec2007-02-12 23:49:43 +00001788 Throwable rethrow = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +00001789
1790 // Cannot update an uninstalled bundle.
1791 BundleInfo info = bundle.getInfo();
Richard S. Hall06862742008-09-29 17:37:19 +00001792 final int oldState = info.getState();
1793 if (oldState == Bundle.UNINSTALLED)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001794 {
1795 throw new IllegalStateException("The bundle is uninstalled.");
1796 }
1797
1798 // First get the update-URL from our header.
1799 String updateLocation = (String)
1800 info.getCurrentHeader().get(Constants.BUNDLE_UPDATELOCATION);
1801
1802 // If no update location specified, use original location.
1803 if (updateLocation == null)
1804 {
1805 updateLocation = info.getLocation();
1806 }
1807
1808 // Stop the bundle, but do not change the persistent state.
1809 stopBundle(bundle, false);
1810
1811 try
1812 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001813 // Get the bundle's archive.
Richard S. Hall04bdbb12006-03-15 14:26:15 +00001814 BundleArchive archive = m_cache.getArchive(info.getBundleId());
Richard S. Hall930fecc2005-08-16 18:33:34 +00001815 // Update the bundle; this operation will increase
1816 // the revision count for the bundle.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001817 archive.revise(updateLocation, is);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001818 // Create a module for the new revision; the revision is
1819 // base zero, so subtract one from the revision count to
1820 // get the revision of the new update.
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001821 try
1822 {
Karl Paulsc19abb42006-07-21 10:23:11 +00001823 Object sm = System.getSecurityManager();
Karl Pauls836bb402006-08-24 12:39:46 +00001824
Karl Paulsc19abb42006-07-21 10:23:11 +00001825 if (sm != null)
1826 {
1827 ((SecurityManager) sm).checkPermission(
1828 new AdminPermission(bundle, AdminPermission.LIFECYCLE));
1829 }
Karl Pauls836bb402006-08-24 12:39:46 +00001830
Karl Paulsad142d22007-09-16 19:53:22 +00001831 // We need to check whether this is an update to an
Karl Pauls49400ec2007-02-12 23:49:43 +00001832 // extension bundle (info.isExtension) or an update from
1833 // a normal bundle to an extension bundle
1834 // (isExtensionBundle())
Richard S. Hall219b0a22008-09-05 21:38:05 +00001835 Map headerMap = archive.getRevision(
1836 archive.getRevisionCount() - 1).getManifestHeader();
Karl Pauls49400ec2007-02-12 23:49:43 +00001837 IModule module = createModule(
1838 info.getBundleId(),
1839 archive.getRevisionCount() - 1,
Richard S. Hall219b0a22008-09-05 21:38:05 +00001840 headerMap,
Richard S. Hall2846a2b2008-06-01 03:08:17 +00001841 (bundle.getInfo().isExtension() ||
Karl Pauls28636dc2008-02-03 21:32:48 +00001842 m_extensionManager.isExtensionBundle(
Richard S. Hall219b0a22008-09-05 21:38:05 +00001843 headerMap)));
Karl Pauls49400ec2007-02-12 23:49:43 +00001844
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001845 // Add module to bundle info.
1846 info.addModule(module);
Karl Pauls49400ec2007-02-12 23:49:43 +00001847
1848 // If this is an update from a normal to an extension bundle
1849 // then attach the extension or else if this already is
Richard S. Hall3875d692008-06-24 19:47:44 +00001850 // an extension bundle then don't allow it to be resolved
Karl Pauls49400ec2007-02-12 23:49:43 +00001851 // again as per spec.
1852 if (!bundle.getInfo().isExtension() &&
Richard S. Hall26b91982007-07-04 21:15:05 +00001853 m_extensionManager.isExtensionBundle(bundle.getInfo().getCurrentHeader()))
Karl Pauls49400ec2007-02-12 23:49:43 +00001854 {
Karl Pauls28636dc2008-02-03 21:32:48 +00001855 addSecurity(bundle);
Richard S. Hall26b91982007-07-04 21:15:05 +00001856 m_extensionManager.addExtensionBundle(this, bundle);
Richard S. Hallafb4ab42008-10-08 21:18:29 +00001857 m_factory.refreshModule(m_sbi.getCurrentModule());
Richard S. Hall26b91982007-07-04 21:15:05 +00001858 bundle.getInfo().setState(Bundle.RESOLVED);
Karl Pauls49400ec2007-02-12 23:49:43 +00001859 }
1860 else if (bundle.getInfo().isExtension())
1861 {
Richard S. Hall26b91982007-07-04 21:15:05 +00001862 bundle.getInfo().setState(Bundle.INSTALLED);
Karl Pauls49400ec2007-02-12 23:49:43 +00001863 }
Karl Pauls28636dc2008-02-03 21:32:48 +00001864 else
1865 {
1866 addSecurity(bundle);
1867 }
Karl Pauls836bb402006-08-24 12:39:46 +00001868 }
Karl Pauls49400ec2007-02-12 23:49:43 +00001869 catch (Throwable ex)
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001870 {
Karl Pauls836bb402006-08-24 12:39:46 +00001871 try
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001872 {
1873 archive.undoRevise();
1874 }
1875 catch (Exception busted)
1876 {
1877 m_logger.log(Logger.LOG_ERROR, "Unable to rollback.", busted);
1878 }
Karl Pauls836bb402006-08-24 12:39:46 +00001879
Karl Pauls3390b4a2006-07-19 13:20:32 +00001880 throw ex;
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001881 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001882 }
Karl Pauls49400ec2007-02-12 23:49:43 +00001883 catch (Throwable ex)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001884 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001885 m_logger.log(Logger.LOG_ERROR, "Unable to update the bundle.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001886 rethrow = ex;
1887 }
1888
Karl Pauls836bb402006-08-24 12:39:46 +00001889 // Set new state, mark as needing a refresh, and fire updated event
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001890 // if successful.
Richard S. Hall930fecc2005-08-16 18:33:34 +00001891 if (rethrow == null)
1892 {
Karl Pauls9ff9bb82006-07-19 12:46:01 +00001893 info.setLastModified(System.currentTimeMillis());
Karl Pauls49400ec2007-02-12 23:49:43 +00001894
1895 if (!info.isExtension())
1896 {
1897 info.setState(Bundle.INSTALLED);
1898 }
1899
Richard S. Hall2dea05f2006-07-25 10:18:20 +00001900 fireBundleEvent(BundleEvent.UNRESOLVED, bundle);
Karl Pauls836bb402006-08-24 12:39:46 +00001901
Richard S. Halleea4d8e2008-10-10 21:34:39 +00001902 // Mark the bundle as removal pending.
1903 info.setRemovalPending(true);
Karl Pauls836bb402006-08-24 12:39:46 +00001904
Richard S. Hall930fecc2005-08-16 18:33:34 +00001905 fireBundleEvent(BundleEvent.UPDATED, bundle);
Richard S. Hall21cfb562007-02-09 19:46:47 +00001906
1907 // Determine if the bundle is in use by anyone.
Richard S. Hall21cfb562007-02-09 19:46:47 +00001908 boolean used = false;
Richard S. Hall771843f2007-06-14 18:13:03 +00001909 IModule[] modules = info.getModules();
1910 for (int i = 0; !used && (i < modules.length); i++)
Richard S. Hall21cfb562007-02-09 19:46:47 +00001911 {
Richard S. Hall771843f2007-06-14 18:13:03 +00001912 IModule[] dependents = ((ModuleImpl) modules[i]).getDependents();
Karl Paulsad142d22007-09-16 19:53:22 +00001913 for (int j = 0; (dependents != null) && (j < dependents.length) && !used; j++)
Richard S. Hall21cfb562007-02-09 19:46:47 +00001914 {
Karl Paulsad142d22007-09-16 19:53:22 +00001915 if (dependents[j] != modules[i])
1916 {
1917 used = true;
1918 }
Richard S. Hall21cfb562007-02-09 19:46:47 +00001919 }
1920 }
1921
1922 // If the bundle is not used by anyone, then garbage
1923 // collect it now.
1924 if (!used)
1925 {
1926 try
1927 {
1928 refreshPackages(new Bundle[] { bundle });
1929 }
1930 catch (Exception ex)
1931 {
1932 m_logger.log(
1933 Logger.LOG_ERROR,
1934 "Unable to immediately purge the bundle revisions.", ex);
1935 }
1936 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00001937 }
Karl Pauls836bb402006-08-24 12:39:46 +00001938
Richard S. Hall06862742008-09-29 17:37:19 +00001939 // Restart the bundle if necessary, but do not change its
1940 // persistent state.
1941 if (oldState == Bundle.ACTIVE)
1942 {
1943 startBundle(bundle, false);
1944 }
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00001945
Richard S. Hall930fecc2005-08-16 18:33:34 +00001946 // If update failed, rethrow exception.
1947 if (rethrow != null)
1948 {
Karl Pauls836bb402006-08-24 12:39:46 +00001949 if ((System.getSecurityManager() != null) &&
Karl Paulsc19abb42006-07-21 10:23:11 +00001950 (rethrow instanceof SecurityException))
1951 {
1952 throw (SecurityException) rethrow;
1953 }
Karl Pauls836bb402006-08-24 12:39:46 +00001954
Richard S. Hall12bbff62008-10-10 14:30:42 +00001955 throw new BundleException("Update of bundle " + bundle + " failed.", rethrow);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001956 }
1957 }
1958 finally
1959 {
1960 try
1961 {
1962 if (is != null) is.close();
1963 }
1964 catch (IOException ex)
1965 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00001966 m_logger.log(Logger.LOG_ERROR, "Unable to close input stream.", ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00001967 }
1968 }
1969 }
1970
Richard S. Hall26b91982007-07-04 21:15:05 +00001971 protected void stopBundle(FelixBundle bundle, boolean record)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001972 throws BundleException
1973 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00001974 // Acquire bundle lock.
1975 acquireBundleLock(bundle);
1976
1977 try
1978 {
1979 _stopBundle(bundle, record);
1980 }
1981 finally
1982 {
1983 // Always release bundle lock.
1984 releaseBundleLock(bundle);
1985 }
1986 }
1987
Richard S. Hall26b91982007-07-04 21:15:05 +00001988 private void _stopBundle(FelixBundle bundle, boolean record)
Richard S. Hall930fecc2005-08-16 18:33:34 +00001989 throws BundleException
1990 {
1991 Throwable rethrow = null;
Karl Pauls836bb402006-08-24 12:39:46 +00001992
Richard S. Hall930fecc2005-08-16 18:33:34 +00001993 // Set the bundle's persistent state to inactive if necessary.
1994 if (record)
1995 {
1996 bundle.getInfo().setPersistentStateInactive();
1997 }
1998
1999 BundleInfo info = bundle.getInfo();
Karl Pauls836bb402006-08-24 12:39:46 +00002000
Richard S. Hall930fecc2005-08-16 18:33:34 +00002001 switch (info.getState())
2002 {
2003 case Bundle.UNINSTALLED:
2004 throw new IllegalStateException("Cannot stop an uninstalled bundle.");
2005 case Bundle.STARTING:
2006 case Bundle.STOPPING:
2007 throw new BundleException("Stopping a bundle that is starting or stopping is currently not supported.");
2008 case Bundle.INSTALLED:
2009 case Bundle.RESOLVED:
2010 return;
2011 case Bundle.ACTIVE:
2012 // Set bundle state..
2013 info.setState(Bundle.STOPPING);
Richard S. Halle50da252006-07-25 07:48:06 +00002014 fireBundleEvent(BundleEvent.STOPPING, bundle);
2015 break;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002016 }
Richard S. Halle50da252006-07-25 07:48:06 +00002017
Richard S. Hall930fecc2005-08-16 18:33:34 +00002018 try
2019 {
Richard S. Hall675b0552007-07-23 17:03:39 +00002020 if (info.getActivator() != null)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002021 {
Richard S. Hall675b0552007-07-23 17:03:39 +00002022 m_secureAction.stopActivator(info.getActivator(), info.getBundleContext());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002023 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002024 }
2025 catch (Throwable th)
2026 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002027 m_logger.log(Logger.LOG_ERROR, "Error stopping bundle.", th);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002028 rethrow = th;
2029 }
Richard S. Hall2a28c8d2006-07-25 07:50:41 +00002030
Richard S. Hallfe87d662007-05-31 20:07:11 +00002031 // Do not clean up after the system bundle since it will
2032 // clean up after itself.
2033 if (info.getBundleId() != 0)
2034 {
2035 // Clean up the bundle context.
2036 ((BundleContextImpl) info.getBundleContext()).invalidate();
2037 info.setBundleContext(null);
Richard S. Hall187b87a2006-07-03 09:13:18 +00002038
Karl Paulscc12bd92008-10-10 21:32:52 +00002039 // Clean up the bundle activator.
2040 info.setActivator(null);
2041
Richard S. Hallfe87d662007-05-31 20:07:11 +00002042 // Unregister any services offered by this bundle.
2043 m_registry.unregisterServices(bundle);
Karl Pauls836bb402006-08-24 12:39:46 +00002044
Richard S. Hallfe87d662007-05-31 20:07:11 +00002045 // Release any services being used by this bundle.
2046 m_registry.ungetServices(bundle);
Karl Pauls836bb402006-08-24 12:39:46 +00002047
Richard S. Hallfe87d662007-05-31 20:07:11 +00002048 // The spec says that we must remove all event
2049 // listeners for a bundle when it is stopped.
2050 m_dispatcher.removeListeners(bundle);
Karl Pauls836bb402006-08-24 12:39:46 +00002051
Richard S. Hallfe87d662007-05-31 20:07:11 +00002052 info.setState(Bundle.RESOLVED);
2053 fireBundleEvent(BundleEvent.STOPPED, bundle);
2054 }
Karl Pauls836bb402006-08-24 12:39:46 +00002055
Richard S. Hall930fecc2005-08-16 18:33:34 +00002056 // Throw activator error if there was one.
2057 if (rethrow != null)
2058 {
2059 // The spec says to expect BundleException or
2060 // SecurityException, so rethrow these exceptions.
2061 if (rethrow instanceof BundleException)
2062 {
2063 throw (BundleException) rethrow;
2064 }
2065 else if (rethrow instanceof SecurityException)
2066 {
2067 throw (SecurityException) rethrow;
2068 }
Karl Pauls836bb402006-08-24 12:39:46 +00002069 else if ((System.getSecurityManager() != null) &&
Karl Paulsc19abb42006-07-21 10:23:11 +00002070 (rethrow instanceof java.security.PrivilegedActionException))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002071 {
Karl Paulsc19abb42006-07-21 10:23:11 +00002072 rethrow = ((java.security.PrivilegedActionException) rethrow).getException();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002073 }
Karl Pauls836bb402006-08-24 12:39:46 +00002074
Richard S. Hall930fecc2005-08-16 18:33:34 +00002075 // Rethrow all other exceptions as a BundleException.
Richard S. Hall12bbff62008-10-10 14:30:42 +00002076 throw new BundleException("Activator stop error in bundle " + bundle + ".", rethrow);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002077 }
2078 }
2079
Richard S. Hall26b91982007-07-04 21:15:05 +00002080 protected void uninstallBundle(FelixBundle bundle) throws BundleException
Richard S. Hall930fecc2005-08-16 18:33:34 +00002081 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002082 // Acquire bundle lock.
2083 acquireBundleLock(bundle);
2084
2085 try
2086 {
2087 _uninstallBundle(bundle);
2088 }
2089 finally
2090 {
2091 // Always release bundle lock.
2092 releaseBundleLock(bundle);
2093 }
2094 }
2095
Richard S. Hall26b91982007-07-04 21:15:05 +00002096 private void _uninstallBundle(FelixBundle bundle) throws BundleException
Richard S. Hall930fecc2005-08-16 18:33:34 +00002097 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002098 BundleInfo info = bundle.getInfo();
2099 if (info.getState() == Bundle.UNINSTALLED)
2100 {
Richard S. Hall12bbff62008-10-10 14:30:42 +00002101 throw new IllegalStateException("Bundle " + bundle + " is uninstalled.");
Richard S. Hall930fecc2005-08-16 18:33:34 +00002102 }
2103
Karl Pauls49400ec2007-02-12 23:49:43 +00002104 // Extension Bundles are not removed until the framework is shutdown
2105 if (bundle.getInfo().isExtension())
2106 {
2107 bundle.getInfo().setPersistentStateUninstalled();
2108 bundle.getInfo().setState(Bundle.INSTALLED);
2109 return;
2110 }
2111
Richard S. Hall930fecc2005-08-16 18:33:34 +00002112 // The spec says that uninstall should always succeed, so
2113 // catch an exception here if stop() doesn't succeed and
2114 // rethrow it at the end.
2115 try
2116 {
2117 stopBundle(bundle, true);
2118 }
2119 catch (BundleException ex)
2120 {
Richard S. Hall447c52f2006-07-04 09:25:07 +00002121 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002122 }
2123
2124 // Remove the bundle from the installed map.
Richard S. Hall26b91982007-07-04 21:15:05 +00002125 FelixBundle target = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002126 synchronized (m_installedBundleLock_Priority2)
2127 {
Richard S. Hall26b91982007-07-04 21:15:05 +00002128 target = (FelixBundle) m_installedBundleMap.remove(info.getLocation());
Karl Paulsa7e36b82008-04-13 19:09:20 +00002129 m_installedBundleIndex.remove(new Long(target.getBundleId()));
Richard S. Hall930fecc2005-08-16 18:33:34 +00002130 }
2131
2132 // Finally, put the uninstalled bundle into the
2133 // uninstalled list for subsequent refreshing.
2134 if (target != null)
2135 {
2136 // Set the bundle's persistent state to uninstalled.
2137 target.getInfo().setPersistentStateUninstalled();
2138
Richard S. Halleea4d8e2008-10-10 21:34:39 +00002139 // Mark the bundle as removal pending.
2140 target.getInfo().setRemovalPending(true);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002141
2142 // Put bundle in uninstalled bundle array.
Karl Pauls49400ec2007-02-12 23:49:43 +00002143 rememberUninstalledBundle(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002144 }
2145 else
2146 {
2147 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002148 Logger.LOG_ERROR, "Unable to remove bundle from installed map!");
Richard S. Hall930fecc2005-08-16 18:33:34 +00002149 }
2150
2151 // Set state to uninstalled.
2152 info.setState(Bundle.UNINSTALLED);
Richard S. Hall69d84792006-01-13 13:55:13 +00002153 info.setLastModified(System.currentTimeMillis());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002154
2155 // Fire bundle event.
2156 fireBundleEvent(BundleEvent.UNINSTALLED, bundle);
Richard S. Hall21cfb562007-02-09 19:46:47 +00002157
2158 // Determine if the bundle is in use by anyone.
Richard S. Hall771843f2007-06-14 18:13:03 +00002159 boolean used = false;
2160 IModule[] modules = info.getModules();
2161 for (int i = 0; !used && (i < modules.length); i++)
2162 {
2163 IModule[] dependents = ((ModuleImpl) modules[i]).getDependents();
Karl Paulsad142d22007-09-16 19:53:22 +00002164 for (int j = 0; (dependents != null) && (j < dependents.length) && !used; j++)
Richard S. Hall771843f2007-06-14 18:13:03 +00002165 {
Karl Paulsad142d22007-09-16 19:53:22 +00002166 if (dependents[j] != modules[i])
2167 {
2168 used = true;
2169 }
Richard S. Hall771843f2007-06-14 18:13:03 +00002170 }
2171 }
Richard S. Hall21cfb562007-02-09 19:46:47 +00002172
Richard S. Hall771843f2007-06-14 18:13:03 +00002173 // If the bundle is not used by anyone, then garbage
2174 // collect it now.
2175 if (!used)
2176 {
2177 try
2178 {
2179 refreshPackages(new Bundle[] { bundle });
2180 }
2181 catch (Exception ex)
2182 {
2183 m_logger.log(
2184 Logger.LOG_ERROR,
2185 "Unable to immediately garbage collect the bundle.", ex);
2186 }
2187 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002188 }
2189
2190 //
2191 // Implementation of BundleContext interface methods.
2192 //
2193
2194 /**
2195 * Implementation for BundleContext.getProperty(). Returns
2196 * environment property associated with the framework.
2197 *
2198 * @param key The name of the property to retrieve.
2199 * @return The value of the specified property or null.
2200 **/
2201 protected String getProperty(String key)
2202 {
2203 // First, check the config properties.
Richard S. Hall471e3e62007-07-11 19:25:33 +00002204 String val = (String) m_configMap.get(key);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002205 // If not found, then try the system properties.
2206 return (val == null) ? System.getProperty(key) : val;
2207 }
2208
2209 protected Bundle installBundle(String location, InputStream is)
2210 throws BundleException
2211 {
2212 return installBundle(-1, location, is);
2213 }
2214
2215 private Bundle installBundle(long id, String location, InputStream is)
2216 throws BundleException
2217 {
Richard S. Hall26b91982007-07-04 21:15:05 +00002218 FelixBundle bundle = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002219
2220 // Acquire an install lock.
2221 acquireInstallLock(location);
2222
2223 try
2224 {
2225 // Check to see if the framework is still running;
Richard S. Hall26b91982007-07-04 21:15:05 +00002226 if ((getState() == Bundle.STOPPING) ||
2227 (getState() == Bundle.UNINSTALLED))
Richard S. Hall930fecc2005-08-16 18:33:34 +00002228 {
2229 throw new BundleException("The framework has been shutdown.");
2230 }
2231
2232 // If bundle location is already installed, then
2233 // return it as required by the OSGi specification.
Richard S. Hall26b91982007-07-04 21:15:05 +00002234 bundle = (FelixBundle) getBundle(location);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002235 if (bundle != null)
2236 {
2237 return bundle;
2238 }
2239
2240 // Determine if this is a new or existing bundle.
2241 boolean isNew = (id < 0);
2242
2243 // If the bundle is new we must cache its JAR file.
2244 if (isNew)
2245 {
2246 // First generate an identifier for it.
2247 id = getNextId();
2248
2249 try
2250 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002251 // Add the bundle to the cache.
Richard S. Hall9a3e9852006-03-04 03:44:05 +00002252 m_cache.create(id, location, is);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002253 }
2254 catch (Exception ex)
2255 {
2256 throw new BundleException(
2257 "Unable to cache bundle: " + location, ex);
2258 }
2259 finally
2260 {
2261 try
2262 {
2263 if (is != null) is.close();
2264 }
2265 catch (IOException ex)
2266 {
2267 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002268 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00002269 "Unable to close input stream.", ex);
2270 }
2271 }
2272 }
2273 else
2274 {
2275 // If the bundle we are installing is not new,
2276 // then try to purge old revisions before installing
2277 // it; this is done just in case a "refresh"
2278 // didn't occur last session...this would only be
2279 // due to an error or system crash.
2280 try
2281 {
2282 if (m_cache.getArchive(id).getRevisionCount() > 1)
2283 {
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00002284 m_cache.getArchive(id).purge();
Richard S. Hall930fecc2005-08-16 18:33:34 +00002285 }
2286 }
2287 catch (Exception ex)
2288 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002289 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002290 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00002291 "Could not purge bundle.", ex);
2292 }
2293 }
2294
2295 try
2296 {
Richard S. Hall04bdbb12006-03-15 14:26:15 +00002297 BundleArchive archive = m_cache.getArchive(id);
Richard S. Hall219b0a22008-09-05 21:38:05 +00002298 Map headerMap = archive.getRevision(
2299 archive.getRevisionCount() - 1).getManifestHeader();
2300 bundle = new BundleImpl(
2301 this, createBundleInfo(
2302 archive, headerMap, m_extensionManager.isExtensionBundle(headerMap)));
Karl Pauls49400ec2007-02-12 23:49:43 +00002303
Richard S. Hall9955e902007-01-25 14:42:01 +00002304 verifyExecutionEnvironment(bundle);
Richard S. Hall2846a2b2008-06-01 03:08:17 +00002305
Karl Pauls28636dc2008-02-03 21:32:48 +00002306 addSecurity(bundle);
2307
Karl Pauls49400ec2007-02-12 23:49:43 +00002308 if (!bundle.getInfo().isExtension())
Karl Paulsc19abb42006-07-21 10:23:11 +00002309 {
Karl Pauls49400ec2007-02-12 23:49:43 +00002310 Object sm = System.getSecurityManager();
2311 if (sm != null)
2312 {
2313 ((SecurityManager) sm).checkPermission(
2314 new AdminPermission(bundle, AdminPermission.LIFECYCLE));
2315 }
Karl Paulsc19abb42006-07-21 10:23:11 +00002316 }
Karl Pauls49400ec2007-02-12 23:49:43 +00002317 else
2318 {
Richard S. Hall26b91982007-07-04 21:15:05 +00002319 m_extensionManager.addExtensionBundle(this, bundle);
Richard S. Hallafb4ab42008-10-08 21:18:29 +00002320 m_factory.refreshModule(m_sbi.getCurrentModule());
Karl Pauls49400ec2007-02-12 23:49:43 +00002321 }
2322
Richard S. Hall930fecc2005-08-16 18:33:34 +00002323 }
Karl Pauls49400ec2007-02-12 23:49:43 +00002324 catch (Throwable ex)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002325 {
2326 // If the bundle is new, then remove it from the cache.
Richard S. Hall26b91982007-07-04 21:15:05 +00002327 // TODO: FRAMEWORK - Perhaps it should be removed if it is not new too.
Richard S. Hall930fecc2005-08-16 18:33:34 +00002328 if (isNew)
2329 {
2330 try
2331 {
2332 m_cache.remove(m_cache.getArchive(id));
2333 }
2334 catch (Exception ex1)
2335 {
2336 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002337 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00002338 "Could not remove from cache.", ex1);
2339 }
2340 }
Karl Pauls836bb402006-08-24 12:39:46 +00002341
Karl Pauls49400ec2007-02-12 23:49:43 +00002342 if (bundle != null)
2343 {
Richard S. Halleea4d8e2008-10-10 21:34:39 +00002344 bundle.getInfo().setRemovalPending(true);
Karl Pauls49400ec2007-02-12 23:49:43 +00002345 }
2346
Karl Pauls836bb402006-08-24 12:39:46 +00002347 if ((System.getSecurityManager() != null) &&
Karl Paulsc19abb42006-07-21 10:23:11 +00002348 (ex instanceof SecurityException))
2349 {
2350 throw (SecurityException) ex;
2351 }
Karl Pauls836bb402006-08-24 12:39:46 +00002352
Karl Pauls49400ec2007-02-12 23:49:43 +00002353 ex.printStackTrace();
2354
Richard S. Hall930fecc2005-08-16 18:33:34 +00002355 throw new BundleException("Could not create bundle object.", ex);
2356 }
2357
2358 // If the bundle is new, then set its start level; existing
2359 // bundles already have their start level set.
2360 if (isNew)
2361 {
2362 // This will persistently set the bundle's start level.
2363 bundle.getInfo().setStartLevel(getInitialBundleStartLevel());
Richard S. Hall69d84792006-01-13 13:55:13 +00002364 bundle.getInfo().setLastModified(System.currentTimeMillis());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002365 }
2366
2367 synchronized (m_installedBundleLock_Priority2)
2368 {
2369 m_installedBundleMap.put(location, bundle);
Karl Paulsa7e36b82008-04-13 19:09:20 +00002370 m_installedBundleIndex.put(new Long(bundle.getBundleId()), bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002371 }
Karl Paulsad142d22007-09-16 19:53:22 +00002372
2373 if (bundle.getInfo().isExtension())
Karl Pauls48e37482007-05-06 22:54:09 +00002374 {
Richard S. Hall26b91982007-07-04 21:15:05 +00002375 FelixBundle systemBundle = (FelixBundle) getBundle(0);
Karl Pauls48e37482007-05-06 22:54:09 +00002376 acquireBundleLock(systemBundle);
2377
2378 try
2379 {
Richard S. Hall26b91982007-07-04 21:15:05 +00002380 m_extensionManager.startExtensionBundle(this, bundle);
Karl Pauls48e37482007-05-06 22:54:09 +00002381 }
2382 finally
2383 {
2384 releaseBundleLock(systemBundle);
2385 }
2386 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002387 }
2388 finally
2389 {
2390 // Always release install lock.
2391 releaseInstallLock(location);
2392
2393 // Always try to close the input stream.
2394 try
2395 {
2396 if (is != null) is.close();
2397 }
2398 catch (IOException ex)
2399 {
2400 m_logger.log(
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002401 Logger.LOG_ERROR,
Richard S. Hall930fecc2005-08-16 18:33:34 +00002402 "Unable to close input stream.", ex);
2403 // Not much else we can do.
2404 }
2405 }
Karl Pauls836bb402006-08-24 12:39:46 +00002406
Richard S. Hall930fecc2005-08-16 18:33:34 +00002407 // Fire bundle event.
2408 fireBundleEvent(BundleEvent.INSTALLED, bundle);
Karl Pauls836bb402006-08-24 12:39:46 +00002409
Richard S. Hall930fecc2005-08-16 18:33:34 +00002410 // Return new bundle.
2411 return bundle;
2412 }
2413
2414 /**
Richard S. Hall9955e902007-01-25 14:42:01 +00002415 * Checks the passed in bundle and checks to see if there is a required execution environment.
2416 * If there is, it gets the execution environment string and verifies that the framework provides it.
2417 * @param bundle The bundle to verify
2418 * @throws BundleException if the bundle's required execution environment does
2419 * not match the current execution environment.
2420 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00002421 private void verifyExecutionEnvironment(FelixBundle bundle)
Richard S. Hall9955e902007-01-25 14:42:01 +00002422 throws BundleException
2423 {
2424 String bundleEnvironment = (String)
2425 bundle.getInfo().getCurrentHeader().get(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT);
2426 if (bundleEnvironment != null)
2427 {
2428 bundleEnvironment = bundleEnvironment.trim();
2429 if (!bundleEnvironment.equals(""))
2430 {
2431 if (!isMatchingExecutionEnvironment(bundleEnvironment))
2432 {
2433 throw new BundleException("Execution Environment not supported: " + bundleEnvironment);
2434 }
2435 }
2436 }
2437 }
2438
2439 /**
2440 * Check the required bundle execution environment against the framework provided
2441 * exectution environment.
2442 * @param bundleEnvironment The required execution environment string
2443 * (from Bundle-RequiredExecutionEnvironment manifest header
2444 * @return True if the required bundle execution environment is provided by the framework
2445 * False if none of the provided framework execution environments match
2446 **/
2447 private boolean isMatchingExecutionEnvironment(String bundleEnvironment)
Karl Pauls49400ec2007-02-12 23:49:43 +00002448 {
Richard S. Hall9955e902007-01-25 14:42:01 +00002449 String frameworkEnvironment = getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
2450 if (frameworkEnvironment == null)
2451 {
2452 // If no framework execution environment is set, then all are valid
2453 return true;
2454 }
2455
2456 frameworkEnvironment = frameworkEnvironment.trim();
2457 if ("".equals(frameworkEnvironment))
2458 {
2459 // If no framework execution environment is set, then all are valid
2460 return true;
2461 }
2462
2463 // The execution environment has changed, so update the cache and EE set
2464 if (!m_executionEnvironment.equals(frameworkEnvironment))
2465 {
2466 updateFrameworkExecutionEnvironment(frameworkEnvironment);
2467 }
2468
2469 StringTokenizer tokens = new StringTokenizer(bundleEnvironment, ",");
2470 while (tokens.hasMoreTokens())
2471 {
2472 if (m_executionEnvironmentCache.contains(tokens.nextToken().trim()))
2473 {
2474 return true;
2475 }
2476 }
2477
2478 return false;
2479 }
2480
2481 /**
2482 * Updates the framework wide execution environment string and a cached Set of
2483 * execution environment tokens from the comma delimited list specified by the
2484 * system variable 'org.osgi.framework.executionenvironment'.
2485 * @param frameworkEnvironment Comma delimited string of provided execution environments
2486 **/
2487 private void updateFrameworkExecutionEnvironment(String frameworkEnvironment)
2488 {
2489 StringTokenizer tokens = new StringTokenizer(frameworkEnvironment, ",");
2490
2491 Set newSet = new HashSet(tokens.countTokens());
2492 while (tokens.hasMoreTokens())
2493 {
2494 newSet.add(tokens.nextToken().trim());
2495 }
2496
2497 synchronized (m_executionEnvironmentCache)
2498 {
2499 m_executionEnvironment = frameworkEnvironment;
2500 m_executionEnvironmentCache = newSet;
2501 }
2502 }
2503
2504 /**
Richard S. Hall930fecc2005-08-16 18:33:34 +00002505 * Retrieves a bundle from its location.
2506 *
2507 * @param location The location of the bundle to retrieve.
2508 * @return The bundle associated with the location or null if there
2509 * is no bundle associated with the location.
2510 **/
2511 protected Bundle getBundle(String location)
2512 {
2513 synchronized (m_installedBundleLock_Priority2)
2514 {
2515 return (Bundle) m_installedBundleMap.get(location);
2516 }
2517 }
2518
2519 /**
2520 * Implementation for BundleContext.getBundle(). Retrieves a
2521 * bundle from its identifier.
2522 *
2523 * @param id The identifier of the bundle to retrieve.
2524 * @return The bundle associated with the identifier or null if there
2525 * is no bundle associated with the identifier.
2526 **/
2527 protected Bundle getBundle(long id)
2528 {
2529 synchronized (m_installedBundleLock_Priority2)
2530 {
Karl Paulsa7e36b82008-04-13 19:09:20 +00002531 FelixBundle bundle = (FelixBundle) m_installedBundleIndex.get(new Long(id));
2532 if (bundle != null)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002533 {
Karl Paulsa7e36b82008-04-13 19:09:20 +00002534 return bundle;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002535 }
2536 }
2537
Richard S. Halla6443462006-06-29 15:16:05 +00002538 synchronized (m_uninstalledBundlesLock_Priority3)
2539 {
Richard S. Hall5a1baf02006-07-20 08:02:42 +00002540 for (int i = 0;
2541 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
2542 i++)
Richard S. Halla6443462006-06-29 15:16:05 +00002543 {
Karl Paulsa7e36b82008-04-13 19:09:20 +00002544 if (m_uninstalledBundles[i].getBundleId() == id)
Richard S. Halla6443462006-06-29 15:16:05 +00002545 {
2546 return m_uninstalledBundles[i];
2547 }
2548 }
2549 }
2550
Richard S. Hall930fecc2005-08-16 18:33:34 +00002551 return null;
2552 }
2553
2554 // Private member for method below.
2555 private Comparator m_comparator = null;
2556
2557 /**
2558 * Implementation for BundleContext.getBundles(). Retrieves
2559 * all installed bundles.
2560 *
2561 * @return An array containing all installed bundles or null if
2562 * there are no installed bundles.
2563 **/
2564 protected Bundle[] getBundles()
2565 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002566 synchronized (m_installedBundleLock_Priority2)
2567 {
2568 if (m_installedBundleMap.size() == 0)
2569 {
2570 return null;
2571 }
2572
Karl Paulsa7e36b82008-04-13 19:09:20 +00002573 return (Bundle[]) m_installedBundleIndex.values().toArray(
2574 new Bundle[m_installedBundleIndex.size()]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002575 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002576 }
2577
2578 protected void addBundleListener(Bundle bundle, BundleListener l)
2579 {
Richard S. Hall92770632006-07-24 10:18:52 +00002580 m_dispatcher.addListener(bundle, BundleListener.class, l, null);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002581 }
2582
Karl Pauls3390b4a2006-07-19 13:20:32 +00002583 protected void removeBundleListener(Bundle bundle, BundleListener l)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002584 {
Richard S. Hall92770632006-07-24 10:18:52 +00002585 m_dispatcher.removeListener(bundle, BundleListener.class, l);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002586 }
2587
2588 /**
2589 * Implementation for BundleContext.addServiceListener().
2590 * Adds service listener to the listener list so that is
2591 * can listen for <code>ServiceEvent</code>s.
2592 *
2593 * @param bundle The bundle that registered the listener.
2594 * @param l The service listener to add to the listener list.
2595 * @param f The filter for the listener; may be null.
2596 **/
2597 protected void addServiceListener(Bundle bundle, ServiceListener l, String f)
2598 throws InvalidSyntaxException
2599 {
Richard S. Hall92770632006-07-24 10:18:52 +00002600 m_dispatcher.addListener(
2601 bundle, ServiceListener.class, l, (f == null) ? null : new FilterImpl(m_logger, f));
Richard S. Hall930fecc2005-08-16 18:33:34 +00002602 }
2603
2604 /**
2605 * Implementation for BundleContext.removeServiceListener().
2606 * Removes service listeners from the listener list.
Karl Pauls836bb402006-08-24 12:39:46 +00002607 *
Karl Pauls3390b4a2006-07-19 13:20:32 +00002608 * @param bundle The context bundle of the listener
Richard S. Hall930fecc2005-08-16 18:33:34 +00002609 * @param l The service listener to remove from the listener list.
2610 **/
Karl Pauls3390b4a2006-07-19 13:20:32 +00002611 protected void removeServiceListener(Bundle bundle, ServiceListener l)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002612 {
Richard S. Hall92770632006-07-24 10:18:52 +00002613 m_dispatcher.removeListener(bundle, ServiceListener.class, l);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002614 }
2615
2616 protected void addFrameworkListener(Bundle bundle, FrameworkListener l)
2617 {
Richard S. Hall92770632006-07-24 10:18:52 +00002618 m_dispatcher.addListener(bundle, FrameworkListener.class, l, null);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002619 }
2620
Karl Pauls3390b4a2006-07-19 13:20:32 +00002621 protected void removeFrameworkListener(Bundle bundle, FrameworkListener l)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002622 {
Richard S. Hall92770632006-07-24 10:18:52 +00002623 m_dispatcher.removeListener(bundle, FrameworkListener.class, l);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002624 }
2625
2626 /**
2627 * Implementation for BundleContext.registerService(). Registers
2628 * a service for the specified bundle bundle.
2629 *
2630 * @param classNames A string array containing the names of the classes
2631 * under which the new service is available.
2632 * @param svcObj The service object or <code>ServiceFactory</code>.
2633 * @param dict A dictionary of properties that further describe the
2634 * service or null.
2635 * @return A <code>ServiceRegistration</code> object or null.
2636 **/
2637 protected ServiceRegistration registerService(
Richard S. Hall26b91982007-07-04 21:15:05 +00002638 FelixBundle bundle, String[] classNames, Object svcObj, Dictionary dict)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002639 {
2640 if (classNames == null)
2641 {
2642 throw new NullPointerException("Service class names cannot be null.");
2643 }
2644 else if (svcObj == null)
2645 {
2646 throw new IllegalArgumentException("Service object cannot be null.");
2647 }
2648
Richard S. Hall930fecc2005-08-16 18:33:34 +00002649 // Acquire bundle lock.
Richard S. Hall3c26cc02006-02-17 13:51:21 +00002650 acquireBundleLock(bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002651
2652 ServiceRegistration reg = null;
2653
2654 try
2655 {
2656 BundleInfo info = bundle.getInfo();
2657
2658 // Can only register services if starting or active.
Karl Pauls28636dc2008-02-03 21:32:48 +00002659 if (((info.getState() & (Bundle.STARTING | Bundle.ACTIVE)) == 0) && !info.isExtension())
Richard S. Hall930fecc2005-08-16 18:33:34 +00002660 {
2661 throw new IllegalStateException(
2662 "Can only register services while bundle is active or activating.");
2663 }
2664
2665 // Check to make sure that the service object is
2666 // an instance of all service classes; ignore if
2667 // service object is a service factory.
2668 if (!(svcObj instanceof ServiceFactory))
2669 {
2670 for (int i = 0; i < classNames.length; i++)
2671 {
Richard S. Hallbc549622006-07-13 13:33:22 +00002672 Class clazz = Util.loadClassUsingClass(svcObj.getClass(), classNames[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002673 if (clazz == null)
2674 {
2675 throw new IllegalArgumentException(
2676 "Cannot cast service: " + classNames[i]);
2677 }
2678 else if (!clazz.isAssignableFrom(svcObj.getClass()))
2679 {
2680 throw new IllegalArgumentException(
2681 "Service object is not an instance of \""
2682 + classNames[i] + "\".");
2683 }
2684 }
2685 }
2686
2687 reg = m_registry.registerService(bundle, classNames, svcObj, dict);
2688 }
2689 finally
2690 {
2691 // Always release bundle lock.
2692 releaseBundleLock(bundle);
2693 }
Richard S. Hall3c26cc02006-02-17 13:51:21 +00002694
2695 // TODO: CONCURRENCY - Reconsider firing event here, outside of the
2696 // bundle lock.
2697
Richard S. Hall930fecc2005-08-16 18:33:34 +00002698 // NOTE: The service registered event is fired from the service
2699 // registry to the framework, where it is then redistributed to
2700 // interested service event listeners.
2701
2702 return reg;
2703 }
2704
Richard S. Hallad76efe2007-01-29 17:37:55 +00002705 /**
2706 * Retrieves an array of {@link ServiceReference} objects based on calling bundle,
2707 * service class name, and filter expression. Optionally checks for isAssignable to
2708 * make sure that the service can be cast to the
2709 * @param bundle Calling Bundle
2710 * @param className Service Classname or <code>null</code> for all
2711 * @param expr Filter Criteria or <code>null</code>
2712 * @return Array of ServiceReference objects that meet the criteria
2713 * @throws InvalidSyntaxException
2714 */
Richard S. Hall930fecc2005-08-16 18:33:34 +00002715 protected ServiceReference[] getServiceReferences(
Richard S. Hall26b91982007-07-04 21:15:05 +00002716 FelixBundle bundle, String className, String expr, boolean checkAssignable)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002717 throws InvalidSyntaxException
2718 {
2719 // Define filter if expression is not null.
2720 Filter filter = null;
2721 if (expr != null)
2722 {
2723 filter = new FilterImpl(m_logger, expr);
2724 }
2725
2726 // Ask the service registry for all matching service references.
2727 List refList = m_registry.getServiceReferences(className, filter);
2728
Richard S. Hallad76efe2007-01-29 17:37:55 +00002729 // Filter on assignable references
2730 if (checkAssignable)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002731 {
Richard S. Hallad76efe2007-01-29 17:37:55 +00002732 for (int refIdx = 0; (refList != null) && (refIdx < refList.size()); refIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002733 {
Richard S. Hallad76efe2007-01-29 17:37:55 +00002734 // Get the current service reference.
2735 ServiceReference ref = (ServiceReference) refList.get(refIdx);
2736
2737 // Now check for castability.
Richard S. Hall211b5a52007-07-09 19:19:29 +00002738 if (!Util.isServiceAssignable(bundle, ref))
Richard S. Hallad76efe2007-01-29 17:37:55 +00002739 {
2740 refList.remove(refIdx);
2741 refIdx--;
2742 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002743 }
2744 }
2745
2746 if (refList.size() > 0)
2747 {
2748 return (ServiceReference[]) refList.toArray(new ServiceReference[refList.size()]);
2749 }
2750
2751 return null;
2752 }
2753
2754 /**
Richard S. Hallad76efe2007-01-29 17:37:55 +00002755 * Retrieves Array of {@link ServiceReference} objects based on calling bundle, service class name,
2756 * optional filter expression, and optionally filters further on the version.
2757 * If running under a {@link SecurityManager}, checks that the calling bundle has permissions to
2758 * see the service references and removes references that aren't.
2759 * @param bundle Calling Bundle
2760 * @param className Service Classname or <code>null</code> for all
2761 * @param expr Filter Criteria or <code>null</code>
2762 * @param checkAssignable <code>true</code> to check for isAssignable, <code>false</code> to return all versions
2763 * @return Array of ServiceReference objects that meet the criteria
2764 * @throws InvalidSyntaxException
2765 */
2766 protected ServiceReference[] getAllowedServiceReferences(
Richard S. Hall26b91982007-07-04 21:15:05 +00002767 FelixBundle bundle, String className, String expr, boolean checkAssignable)
Richard S. Hallad76efe2007-01-29 17:37:55 +00002768 throws InvalidSyntaxException
2769 {
2770 ServiceReference[] refs = getServiceReferences(bundle, className, expr, checkAssignable);
2771
2772 Object sm = System.getSecurityManager();
2773
Karl Pauls80ca00c2007-01-30 14:03:32 +00002774 if ((sm == null) || (refs == null))
Richard S. Hallad76efe2007-01-29 17:37:55 +00002775 {
2776 return refs;
2777 }
2778
2779 List result = new ArrayList();
2780
2781 for (int i = 0;i < refs.length;i++)
2782 {
2783 String[] objectClass = (String[]) refs[i].getProperty(Constants.OBJECTCLASS);
2784
2785 if (objectClass == null)
2786 {
2787 continue;
2788 }
2789
2790 for (int j = 0; j < objectClass.length; j++)
2791 {
2792 try
2793 {
2794 ((SecurityManager) sm).checkPermission(new ServicePermission(
2795 objectClass[j], ServicePermission.GET));
2796 result.add(refs[i]);
2797 break;
2798 }
2799 catch (Exception ex)
2800 {
2801 // Ignore, since we are just testing permission.
2802 }
2803 }
2804 }
2805
2806 if (result.isEmpty())
2807 {
2808 return null;
2809 }
2810
2811 return (ServiceReference[]) result.toArray(new ServiceReference[result.size()]);
2812
2813 }
2814
Richard S. Hall930fecc2005-08-16 18:33:34 +00002815 protected Object getService(Bundle bundle, ServiceReference ref)
2816 {
2817 // Check that the bundle has permission to get at least
2818 // one of the service interfaces; the objectClass property
2819 // of the service stores its service interfaces.
2820 String[] objectClass = (String[])
2821 ref.getProperty(Constants.OBJECTCLASS);
2822 if (objectClass == null)
2823 {
2824 return null;
2825 }
2826
Richard S. Hall930fecc2005-08-16 18:33:34 +00002827 return m_registry.getService(bundle, ref);
2828 }
2829
2830 protected boolean ungetService(Bundle bundle, ServiceReference ref)
2831 {
2832 return m_registry.ungetService(bundle, ref);
2833 }
2834
Richard S. Hall26b91982007-07-04 21:15:05 +00002835 protected File getDataFile(FelixBundle bundle, String s)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002836 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00002837 try
2838 {
Karl Pauls28636dc2008-02-03 21:32:48 +00002839 if (bundle == this)
2840 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +00002841 return m_cache.getSystemBundleDataFile(s);
Karl Pauls28636dc2008-02-03 21:32:48 +00002842 }
Richard S. Hall2846a2b2008-06-01 03:08:17 +00002843
Richard S. Hallafb4ab42008-10-08 21:18:29 +00002844 return m_cache.getArchive(bundle.getBundleId()).getDataFile(s);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002845 }
2846 catch (Exception ex)
2847 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00002848 m_logger.log(Logger.LOG_ERROR, ex.getMessage());
Richard S. Hall930fecc2005-08-16 18:33:34 +00002849 return null;
2850 }
2851 }
2852
2853 //
2854 // PackageAdmin related methods.
2855 //
2856
2857 /**
Richard S. Hallc87d41a2006-07-03 07:57:28 +00002858 * This method returns the bundle associated with the specified class if
2859 * the class was loaded from a bundle from this framework instance. If the
2860 * class was not loaded from a bundle or was loaded by a bundle in another
2861 * framework instance, then <tt>null</tt> is returned.
Karl Pauls836bb402006-08-24 12:39:46 +00002862 *
Richard S. Hallc87d41a2006-07-03 07:57:28 +00002863 * @param clazz the class for which to find its associated bundle.
2864 * @return the bundle associated with the specified class or <tt>null</tt>
2865 * if the class was not loaded by a bundle or its associated
2866 * bundle belongs to a different framework instance.
2867 **/
2868 protected Bundle getBundle(Class clazz)
2869 {
2870 if (clazz.getClassLoader() instanceof ContentClassLoader)
2871 {
2872 IContentLoader contentLoader =
2873 ((ContentClassLoader) clazz.getClassLoader()).getContentLoader();
2874 IModule[] modules = m_factory.getModules();
2875 for (int i = 0; i < modules.length; i++)
2876 {
2877 if (modules[i].getContentLoader() == contentLoader)
2878 {
2879 long id = Util.getBundleIdFromModuleId(modules[i].getId());
2880 return getBundle(id);
2881 }
2882 }
2883 }
Richard S. Hallafb4ab42008-10-08 21:18:29 +00002884 try
Karl Paulsb6ad9922008-08-20 16:37:33 +00002885 {
2886 return (getInfo().getCurrentModule().getClass(clazz.getName()) == clazz) ? this : null;
2887 }
Richard S. Hallafb4ab42008-10-08 21:18:29 +00002888 catch(ClassNotFoundException ex)
Karl Paulsb6ad9922008-08-20 16:37:33 +00002889 {
2890 return null;
2891 }
Richard S. Hallc87d41a2006-07-03 07:57:28 +00002892 }
2893
2894 /**
Richard S. Hall1bdc3722006-07-03 09:52:07 +00002895 * Returns the exported packages associated with the specified
Richard S. Hallafc52d42006-02-09 13:04:32 +00002896 * package name. This is used by the PackageAdmin service
2897 * implementation.
2898 *
Richard S. Hallbf12bf72007-01-22 07:15:25 +00002899 * @param pkgName The name of the exported package to find.
Richard S. Hallafc52d42006-02-09 13:04:32 +00002900 * @return The exported package or null if no matching package was found.
2901 **/
Richard S. Hallbf12bf72007-01-22 07:15:25 +00002902 protected ExportedPackage[] getExportedPackages(String pkgName)
Richard S. Hallafc52d42006-02-09 13:04:32 +00002903 {
Richard S. Hallbf12bf72007-01-22 07:15:25 +00002904 // First, get all exporters of the package.
Richard S. Hall441cc662007-01-31 21:12:57 +00002905 R4SearchPolicyCore.PackageSource[] exporters =
Richard S. Hall5c9d99b2008-09-24 20:53:36 +00002906 m_policyCore.getResolvedCandidates(
Richard S. Hallbf12bf72007-01-22 07:15:25 +00002907 new Requirement(
2908 ICapability.PACKAGE_NAMESPACE,
2909 null,
Richard S. Hall21cfb562007-02-09 19:46:47 +00002910 new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, pkgName, false) }));
Richard S. Hallbf12bf72007-01-22 07:15:25 +00002911
Richard S. Hall930fecc2005-08-16 18:33:34 +00002912 if (exporters != null)
2913 {
Karl Paulsad142d22007-09-16 19:53:22 +00002914 List pkgs = new ArrayList();
2915
2916 Requirement req = new Requirement(ICapability.PACKAGE_NAMESPACE,
2917 null,
Karl Paulsad142d22007-09-16 19:53:22 +00002918 new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, pkgName, false) });
2919
2920 for (int pkgIdx = 0; pkgIdx < exporters.length; pkgIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002921 {
Richard S. Hallafc52d42006-02-09 13:04:32 +00002922 // Get the bundle associated with the current exporting module.
Richard S. Hall26b91982007-07-04 21:15:05 +00002923 FelixBundle bundle = (FelixBundle) getBundle(
Richard S. Hallbf12bf72007-01-22 07:15:25 +00002924 Util.getBundleIdFromModuleId(exporters[pkgIdx].m_module.getId()));
Richard S. Hallafc52d42006-02-09 13:04:32 +00002925
2926 // We need to find the version of the exported package, but this
2927 // is tricky since there may be multiple versions of the package
2928 // offered by a given bundle, since multiple revisions of the
2929 // bundle JAR file may exist if the bundle was updated without
2930 // refreshing the framework. In this case, each revision of the
2931 // bundle JAR file is represented as a module in the BundleInfo
2932 // module array, which is ordered from oldest to newest. We assume
2933 // that the first module found to be exporting the package is the
2934 // provider of the package, which makes sense since it must have
2935 // been resolved first.
2936 IModule[] modules = bundle.getInfo().getModules();
2937 for (int modIdx = 0; modIdx < modules.length; modIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00002938 {
Karl Paulsad142d22007-09-16 19:53:22 +00002939 ICapability[] ec = modules[modIdx].getDefinition().getCapabilities();
2940 for (int i = 0; (ec != null) && (i < ec.length); i++)
Richard S. Hallafc52d42006-02-09 13:04:32 +00002941 {
Karl Paulsad142d22007-09-16 19:53:22 +00002942 if (ec[i].getNamespace().equals(req.getNamespace()) &&
2943 req.isSatisfied(ec[i]))
2944 {
2945 pkgs.add(new ExportedPackageImpl(this, bundle, modules[modIdx], (Capability) ec[i]));
2946 }
Richard S. Hallafc52d42006-02-09 13:04:32 +00002947 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00002948 }
2949 }
Karl Paulsad142d22007-09-16 19:53:22 +00002950
2951 return (pkgs.isEmpty()) ? null : (ExportedPackage[]) pkgs.toArray(new ExportedPackage[pkgs.size()]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00002952 }
2953
Karl Paulsad142d22007-09-16 19:53:22 +00002954 return null;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002955 }
2956
2957 /**
2958 * Returns an array of all actively exported packages from the specified
2959 * bundle or if the specified bundle is <tt>null</tt> an array
2960 * containing all actively exported packages by all bundles.
2961 *
2962 * @param b The bundle whose exported packages are to be retrieved
2963 * or <tt>null</tt> if the exported packages of all bundles are
2964 * to be retrieved.
2965 * @return An array of exported packages.
2966 **/
2967 protected ExportedPackage[] getExportedPackages(Bundle b)
2968 {
2969 List list = new ArrayList();
2970
2971 // If a bundle is specified, then return its
2972 // exported packages.
2973 if (b != null)
2974 {
Richard S. Hall26b91982007-07-04 21:15:05 +00002975 FelixBundle bundle = (FelixBundle) b;
Richard S. Hall930fecc2005-08-16 18:33:34 +00002976 getExportedPackages(bundle, list);
2977 }
2978 // Otherwise return all exported packages.
2979 else
2980 {
2981 // To create a list of all exported packages, we must look
2982 // in the installed and uninstalled sets of bundles. To
2983 // ensure a somewhat consistent view, we will gather all
2984 // of this information from within the installed bundle
2985 // lock.
2986 synchronized (m_installedBundleLock_Priority2)
2987 {
2988 // First get exported packages from uninstalled bundles.
2989 synchronized (m_uninstalledBundlesLock_Priority3)
2990 {
2991 for (int bundleIdx = 0;
2992 (m_uninstalledBundles != null) && (bundleIdx < m_uninstalledBundles.length);
2993 bundleIdx++)
2994 {
Richard S. Hall26b91982007-07-04 21:15:05 +00002995 FelixBundle bundle = m_uninstalledBundles[bundleIdx];
Richard S. Hall930fecc2005-08-16 18:33:34 +00002996 getExportedPackages(bundle, list);
2997 }
2998 }
2999
3000 // Now get exported packages from installed bundles.
3001 Bundle[] bundles = getBundles();
3002 for (int bundleIdx = 0; bundleIdx < bundles.length; bundleIdx++)
3003 {
Richard S. Hall26b91982007-07-04 21:15:05 +00003004 FelixBundle bundle = (FelixBundle) bundles[bundleIdx];
Richard S. Hall930fecc2005-08-16 18:33:34 +00003005 getExportedPackages(bundle, list);
3006 }
3007 }
3008 }
3009
3010 return (ExportedPackage[]) list.toArray(new ExportedPackage[list.size()]);
3011 }
3012
3013 /**
3014 * Adds any current active exported packages from the specified bundle
3015 * to the passed in list.
3016 * @param bundle The bundle from which to retrieve exported packages.
3017 * @param list The list to which the exported packages are added
3018 **/
Richard S. Hall26b91982007-07-04 21:15:05 +00003019 private void getExportedPackages(FelixBundle bundle, List list)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003020 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00003021 // Since a bundle may have many modules associated with it,
3022 // one for each revision in the cache, search each module
3023 // for each revision to get all exports.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003024 IModule[] modules = bundle.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003025 for (int modIdx = 0; modIdx < modules.length; modIdx++)
3026 {
Richard S. Hallbf12bf72007-01-22 07:15:25 +00003027 ICapability[] caps = modules[modIdx].getDefinition().getCapabilities();
3028 if ((caps != null) && (caps.length > 0))
Richard S. Hall930fecc2005-08-16 18:33:34 +00003029 {
Richard S. Hallbf12bf72007-01-22 07:15:25 +00003030 for (int capIdx = 0; capIdx < caps.length; capIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003031 {
3032 // See if the target bundle's module is one of the
3033 // "in use" exporters of the package.
Richard S. Hall352a0332007-01-29 17:41:28 +00003034 if (caps[capIdx].getNamespace().equals(ICapability.PACKAGE_NAMESPACE))
Richard S. Hall930fecc2005-08-16 18:33:34 +00003035 {
Richard S. Hall5c9d99b2008-09-24 20:53:36 +00003036 R4SearchPolicyCore.PackageSource[] inUseModules = m_policyCore.getResolvedCandidates(
Richard S. Hall352a0332007-01-29 17:41:28 +00003037 new Requirement(
3038 ICapability.PACKAGE_NAMESPACE,
3039 null,
Richard S. Hall21cfb562007-02-09 19:46:47 +00003040 new R4Attribute[] { new R4Attribute(ICapability.PACKAGE_PROPERTY, ((Capability) caps[capIdx]).getPackageName(), false) }));
Karl Pauls49400ec2007-02-12 23:49:43 +00003041
Richard S. Hall352a0332007-01-29 17:41:28 +00003042 // Search through the current providers to find the target
3043 // module.
3044 for (int i = 0; (inUseModules != null) && (i < inUseModules.length); i++)
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003045 {
Richard S. Hall352a0332007-01-29 17:41:28 +00003046 if (inUseModules[i].m_module == modules[modIdx])
3047 {
3048 list.add(new ExportedPackageImpl(
3049 this, bundle, modules[modIdx], (Capability) caps[capIdx]));
3050 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003051 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003052 }
3053 }
3054 }
3055 }
3056 }
3057
Richard S. Hall26b91982007-07-04 21:15:05 +00003058 protected Bundle[] getDependentBundles(FelixBundle exporter)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003059 {
Richard S. Halle1f53a52006-07-17 11:06:59 +00003060 // Get exporting bundle.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003061 BundleInfo exporterInfo = exporter.getInfo();
3062
3063 // Create list for storing importing bundles.
3064 List list = new ArrayList();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003065
Richard S. Hall771843f2007-06-14 18:13:03 +00003066 // Get all dependent modules from all exporter module revisions.
3067 IModule[] modules = exporterInfo.getModules();
3068 for (int modIdx = 0; modIdx < modules.length; modIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003069 {
Richard S. Hall771843f2007-06-14 18:13:03 +00003070 IModule[] dependents = ((ModuleImpl) modules[modIdx]).getDependents();
3071 for (int depIdx = 0;
3072 (dependents != null) && (depIdx < dependents.length);
3073 depIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003074 {
Richard S. Hall771843f2007-06-14 18:13:03 +00003075 Bundle b = getBundle(Util.getBundleIdFromModuleId(dependents[depIdx].getId()));
3076 list.add(b);
3077 }
3078 }
Richard S. Hall82699422006-07-19 14:37:45 +00003079
Richard S. Hall771843f2007-06-14 18:13:03 +00003080 // Return the results.
3081 if (list.size() > 0)
3082 {
3083 return (Bundle[]) list.toArray(new Bundle[list.size()]);
3084 }
3085
3086 return null;
3087 }
3088
3089 protected Bundle[] getImportingBundles(ExportedPackage ep)
3090 {
3091 // Create list for storing importing bundles.
3092 List list = new ArrayList();
3093
3094 // Get exporting bundle information.
Richard S. Hall26b91982007-07-04 21:15:05 +00003095 FelixBundle exporter = (FelixBundle)
Richard S. Hall12bbff62008-10-10 14:30:42 +00003096 (ep).getExportingBundle();
Richard S. Hall771843f2007-06-14 18:13:03 +00003097
3098 // Search the dependents of the exporter's module revisions
3099 // for importers of the specific package.
3100 IModule[] expModules = exporter.getInfo().getModules();
3101 for (int expIdx = 0; (expModules != null) && (expIdx < expModules.length); expIdx++)
3102 {
3103 IModule[] depModules = ((ModuleImpl) expModules[expIdx]).getDependents();
3104 for (int depIdx = 0; (depModules != null) && (depIdx < depModules.length); depIdx++)
3105 {
Richard S. Hallfc873412007-12-20 19:54:37 +00003106 // ExportedPackage.getImportingBundles() does not expect bundles
3107 // to depend on themselves, so we will filter that case here.
3108 if (!expModules[expIdx].equals(depModules[depIdx]))
Richard S. Hall930fecc2005-08-16 18:33:34 +00003109 {
Richard S. Hallfc873412007-12-20 19:54:37 +00003110 // See if the dependent module has a wire for the specific
3111 // package. If so, see if the provider module is from the
3112 // exporter and record it if it is.
3113 IWire wire = Util.getWire(depModules[depIdx], ep.getName());
3114 if ((wire != null) && expModules[expIdx].equals(wire.getExporter()) &&
3115 wire.getRequirement().isSatisfied(
3116 new Capability(ICapability.PACKAGE_NAMESPACE, null, new R4Attribute[] {
3117 new R4Attribute(ICapability.PACKAGE_PROPERTY, ep.getName(), false),
3118 new R4Attribute(ICapability.VERSION_PROPERTY, ep.getVersion(), false)
3119 })))
3120 {
3121 // Add the bundle to the list of importers.
3122 list.add(getBundle(Util.getBundleIdFromModuleId(depModules[depIdx].getId())));
3123 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003124 }
3125 }
3126 }
3127
3128 // Return the results.
3129 if (list.size() > 0)
3130 {
3131 return (Bundle[]) list.toArray(new Bundle[list.size()]);
3132 }
3133
3134 return null;
3135 }
3136
Richard S. Hall1a4ab602006-05-24 13:46:06 +00003137 protected boolean resolveBundles(Bundle[] targets)
3138 {
Richard S. Hall1a4ab602006-05-24 13:46:06 +00003139 // Acquire locks for all bundles to be resolved.
Richard S. Hall26b91982007-07-04 21:15:05 +00003140 FelixBundle[] bundles = acquireBundleResolveLocks(targets);
Richard S. Hall1a4ab602006-05-24 13:46:06 +00003141
3142 try
3143 {
3144 boolean result = true;
3145
3146 // If there are targets, then resolve each one.
3147 if (bundles != null)
3148 {
3149 for (int i = 0; i < bundles.length; i++)
3150 {
3151 try
3152 {
3153 _resolveBundle(bundles[i]);
3154 }
3155 catch (BundleException ex)
3156 {
3157 result = false;
3158 m_logger.log(
3159 Logger.LOG_WARNING,
3160 "Unable to resolve bundle " + bundles[i].getBundleId(),
3161 ex);
3162 }
3163 }
3164 }
3165
3166 return result;
3167 }
3168 finally
3169 {
3170 // Always release all bundle locks.
3171 releaseBundleLocks(bundles);
3172 }
3173 }
3174
Richard S. Hall930fecc2005-08-16 18:33:34 +00003175 protected void refreshPackages(Bundle[] targets)
3176 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00003177 // Acquire locks for all impacted bundles.
Richard S. Hall26b91982007-07-04 21:15:05 +00003178 FelixBundle[] bundles = acquireBundleRefreshLocks(targets);
Karl Pauls49400ec2007-02-12 23:49:43 +00003179 boolean restart = false;
Karl Paulsad142d22007-09-16 19:53:22 +00003180
Karl Pauls49400ec2007-02-12 23:49:43 +00003181 Bundle systemBundle = getBundle(0);
3182
3183 // We need to restart the framework if either an extension bundle is
3184 // refreshed or the system bundle is refreshed and any extension bundle
3185 // has been updated or uninstalled.
3186 for (int i = 0; (bundles != null) && !restart && (i < bundles.length); i++)
3187 {
3188 if (bundles[i].getInfo().isExtension())
3189 {
3190 restart = true;
3191 }
3192 else if (systemBundle == bundles[i])
3193 {
3194 Bundle[] allBundles = getBundles();
3195 for (int j = 0; !restart && j < allBundles.length; j++)
3196 {
Richard S. Hall26b91982007-07-04 21:15:05 +00003197 if (((FelixBundle) allBundles[j]).getInfo().isExtension() &&
3198 (allBundles[j].getState() == Bundle.INSTALLED))
Karl Pauls49400ec2007-02-12 23:49:43 +00003199 {
3200 restart = true;
3201 }
3202 }
3203 }
3204 }
3205
3206 if (restart)
3207 {
3208// TODO: Extension Bundle - We need a way to restart the framework
3209 m_logger.log(Logger.LOG_WARNING, "Framework restart not implemented.");
3210 }
3211
Richard S. Hall930fecc2005-08-16 18:33:34 +00003212 // Remove any targeted bundles from the uninstalled bundles
3213 // array, since they will be removed from the system after
3214 // the refresh.
3215 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
3216 {
3217 forgetUninstalledBundle(bundles[i]);
3218 }
3219
3220 try
3221 {
3222 // If there are targets, then refresh each one.
3223 if (bundles != null)
3224 {
3225 // At this point the map contains every bundle that has been
3226 // updated and/or removed as well as all bundles that import
3227 // packages from these bundles.
Karl Pauls836bb402006-08-24 12:39:46 +00003228
Richard S. Hall930fecc2005-08-16 18:33:34 +00003229 // Create refresh helpers for each bundle.
3230 RefreshHelper[] helpers = new RefreshHelper[bundles.length];
3231 for (int i = 0; i < bundles.length; i++)
3232 {
Karl Pauls49400ec2007-02-12 23:49:43 +00003233 if (!bundles[i].getInfo().isExtension())
3234 {
3235 helpers[i] = new RefreshHelper(bundles[i]);
3236 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003237 }
3238
3239 // Stop, purge or remove, and reinitialize all bundles first.
3240 for (int i = 0; i < helpers.length; i++)
3241 {
Karl Pauls49400ec2007-02-12 23:49:43 +00003242 if (helpers[i] != null)
3243 {
3244 helpers[i].stop();
3245 helpers[i].purgeOrRemove();
3246 helpers[i].reinitialize();
3247 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003248 }
3249
3250 // Then restart all bundles that were previously running.
3251 for (int i = 0; i < helpers.length; i++)
3252 {
Karl Pauls49400ec2007-02-12 23:49:43 +00003253 if (helpers[i] != null)
3254 {
3255 helpers[i].restart();
3256 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003257 }
3258 }
3259 }
3260 finally
3261 {
3262 // Always release all bundle locks.
3263 releaseBundleLocks(bundles);
3264 }
3265
Richard S. Hallfaa3d612007-10-24 14:18:17 +00003266 fireFrameworkEvent(FrameworkEvent.PACKAGES_REFRESHED, this, null);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003267 }
3268
Richard S. Hall26b91982007-07-04 21:15:05 +00003269 private void populateImportGraph(FelixBundle exporter, Map map)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003270 {
Richard S. Hall771843f2007-06-14 18:13:03 +00003271 // Get all dependent bundles of this bundle.
3272 Bundle[] importers = getDependentBundles(exporter);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003273
Richard S. Hall771843f2007-06-14 18:13:03 +00003274 for (int impIdx = 0;
3275 (importers != null) && (impIdx < importers.length);
3276 impIdx++)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003277 {
Richard S. Hall771843f2007-06-14 18:13:03 +00003278 // Avoid cycles if the bundle is already in map.
3279 if (!map.containsKey(importers[impIdx]))
Richard S. Hall930fecc2005-08-16 18:33:34 +00003280 {
Richard S. Hall771843f2007-06-14 18:13:03 +00003281 // Add each importing bundle to map.
3282 map.put(importers[impIdx], importers[impIdx]);
3283 // Now recurse into each bundle to get its importers.
3284 populateImportGraph(
Richard S. Hall26b91982007-07-04 21:15:05 +00003285 (FelixBundle) importers[impIdx], map);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003286 }
3287 }
3288 }
3289
3290 //
3291 // Miscellaneous private methods.
3292 //
3293
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003294 private RegularBundleInfo createBundleInfo(BundleArchive archive, Map headerMap, boolean isExtension)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003295 throws Exception
3296 {
Richard S. Hall930fecc2005-08-16 18:33:34 +00003297 // Create the module for the bundle; although there should only
3298 // ever be one revision at this point, create the module for
3299 // the current revision to be safe.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003300 IModule module = createModule(
Richard S. Hall2846a2b2008-06-01 03:08:17 +00003301 archive.getId(), archive.getRevisionCount() - 1, headerMap,
Karl Pauls28636dc2008-02-03 21:32:48 +00003302 isExtension);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003303
3304 // Finally, create an return the bundle info.
Richard S. Halld3cd46c2008-10-10 15:13:10 +00003305 RegularBundleInfo info = new RegularBundleInfo(m_logger, module, archive);
Karl Pauls49400ec2007-02-12 23:49:43 +00003306 info.setExtension(isExtension);
3307
3308 return info;
3309 }
3310
Karl Pauls28636dc2008-02-03 21:32:48 +00003311 private volatile SecurityProvider m_securityProvider;
Karl Pauls49400ec2007-02-12 23:49:43 +00003312
Karl Pauls28636dc2008-02-03 21:32:48 +00003313 void setSecurityProvider(SecurityProvider securityProvider)
3314 {
3315 m_securityProvider = securityProvider;
3316 }
3317
3318 Object getSignerMatcher(FelixBundle bundle)
3319 {
3320 if (m_securityProvider != null)
3321 {
3322 return m_securityProvider.getSignerMatcher(bundle);
3323 }
3324 return null;
3325 }
3326
3327 boolean impliesBundlePermission(BundleProtectionDomain bundleProtectionDomain, Permission permission, boolean direct)
3328 {
3329 if (m_securityProvider != null)
3330 {
3331 return m_securityProvider.hasBundlePermission(bundleProtectionDomain, permission, direct);
3332 }
Karl Pauls118c9162008-08-06 15:59:20 +00003333 else if ((bundleProtectionDomain.getBundle() != this) && (System.getSecurityManager() != null))
3334 {
3335 return m_secureAction.getPolicy().implies(bundleProtectionDomain, permission);
3336 }
Karl Pauls28636dc2008-02-03 21:32:48 +00003337 return true;
3338 }
3339
Karl Pauls758c2be2008-03-05 13:10:04 +00003340 void addSecurity(final FelixBundle bundle) throws Exception
Karl Pauls28636dc2008-02-03 21:32:48 +00003341 {
Karl Pauls758c2be2008-03-05 13:10:04 +00003342 if (m_securityProvider != null)
3343 {
3344 m_securityProvider.checkBundle(bundle);
3345 }
Karl Pauls28636dc2008-02-03 21:32:48 +00003346 bundle.getInfo().setProtectionDomain(new BundleProtectionDomain(this, bundle));
Richard S. Hall930fecc2005-08-16 18:33:34 +00003347 }
3348
3349 /**
3350 * Creates a module for a given bundle by reading the bundle's
3351 * manifest meta-data and converting it to work with the underlying
3352 * import/export search policy of the module loader.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00003353 * @param targetId The identifier of the bundle for which the module should
Richard S. Hall930fecc2005-08-16 18:33:34 +00003354 * be created.
Richard S. Hallbf6bc8a2006-07-03 13:43:46 +00003355 * @param headerMap The headers map associated with the bundle.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003356 * @return The initialized and/or newly created module.
3357 **/
Karl Pauls49400ec2007-02-12 23:49:43 +00003358 private IModule createModule(long targetId, int revision, Map headerMap,
Karl Pauls28636dc2008-02-03 21:32:48 +00003359 boolean isExtensionBundle) throws Exception
Richard S. Hall930fecc2005-08-16 18:33:34 +00003360 {
Richard S. Hall471e3e62007-07-11 19:25:33 +00003361 ManifestParser mp = new ManifestParser(m_logger, m_configMap, headerMap);
Richard S. Halla2878c12006-07-21 14:50:07 +00003362
3363 // Verify that the bundle symbolic name and version is unique.
Richard S. Hall56b11942006-10-26 14:40:07 +00003364 if (mp.getManifestVersion().equals("2"))
Richard S. Hall930fecc2005-08-16 18:33:34 +00003365 {
Richard S. Hall56b11942006-10-26 14:40:07 +00003366 Version bundleVersion = mp.getBundleVersion();
3367 bundleVersion = (bundleVersion == null) ? Version.emptyVersion : bundleVersion;
Richard S. Hall12bbff62008-10-10 14:30:42 +00003368 String symName = mp.getSymbolicName();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003369
Richard S. Hall8bebf412006-07-03 12:54:50 +00003370 Bundle[] bundles = getBundles();
3371 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
3372 {
Karl Paulsa7e36b82008-04-13 19:09:20 +00003373 long id = ((FelixBundle) bundles[i]).getBundleId();
Richard S. Hallc7da25d2008-08-01 15:41:32 +00003374 String sym = bundles[i].getSymbolicName();
Richard S. Hall26b91982007-07-04 21:15:05 +00003375 Version ver = Version.parseVersion((String) ((FelixBundle) bundles[i])
Richard S. Hall56b11942006-10-26 14:40:07 +00003376 .getInfo().getCurrentHeader().get(Constants.BUNDLE_VERSION));
Richard S. Halla2878c12006-07-21 14:50:07 +00003377 if (symName.equals(sym) && bundleVersion.equals(ver) && (targetId != id))
Richard S. Hall8bebf412006-07-03 12:54:50 +00003378 {
Richard S. Hall12bbff62008-10-10 14:30:42 +00003379 throw new BundleException("Bundle symbolic name and version are not unique: " + sym + ':' + ver);
Richard S. Hall8bebf412006-07-03 12:54:50 +00003380 }
3381 }
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003382 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003383
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003384 // Now that we have all of the metadata associated with the
3385 // module, we need to create the module itself. This is somewhat
3386 // complicated because a module is constructed out of several
Richard S. Hall594145f2006-07-23 13:07:18 +00003387 // interrelated pieces (e.g., module definition, content loader,
3388 // search policy, url policy). We need to create all of these
3389 // pieces and bind them together.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003390
Richard S. Hall594145f2006-07-23 13:07:18 +00003391 // Create the module definition for the new module.
Karl Pauls49400ec2007-02-12 23:49:43 +00003392 // Note, in case this is an extension bundle it's exports are removed -
3393 // they will be added to the system bundle directly later on.
Richard S. Hall594145f2006-07-23 13:07:18 +00003394 IModuleDefinition md = new ModuleDefinition(
Richard S. Hall95d97de2008-08-29 16:17:26 +00003395 headerMap,
Karl Pauls49400ec2007-02-12 23:49:43 +00003396 (isExtensionBundle) ? null : mp.getCapabilities(),
Richard S. Hallbf12bf72007-01-22 07:15:25 +00003397 mp.getRequirements(),
3398 mp.getDynamicRequirements(),
Richard S. Hall5eda19c2008-02-29 19:52:53 +00003399 mp.getLibraries());
Karl Pauls836bb402006-08-24 12:39:46 +00003400
Richard S. Hall594145f2006-07-23 13:07:18 +00003401 // Create the module using the module definition.
3402 IModule module = m_factory.createModule(
3403 Long.toString(targetId) + "." + Integer.toString(revision), md);
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003404
Richard S. Hall594145f2006-07-23 13:07:18 +00003405 // Create the content loader from the module archive.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003406 IContentLoader contentLoader = new ContentLoaderImpl(
Richard S. Hall5eda19c2008-02-29 19:52:53 +00003407 m_logger, m_cache.getArchive(targetId).getRevision(revision).getContent());
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003408 // Set the content loader's search policy.
3409 contentLoader.setSearchPolicy(
3410 new R4SearchPolicy(m_policyCore, module));
3411 // Set the content loader's URL policy.
3412 contentLoader.setURLPolicy(
Richard S. Hallfb5221e2006-02-20 10:22:28 +00003413// TODO: ML - SUCKS NEEDING URL POLICY PER MODULE.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003414 new URLPolicyImpl(
3415 m_logger, m_bundleStreamHandler, module));
3416
3417 // Set the module's content loader to the created content loader.
3418 m_factory.setContentLoader(module, contentLoader);
3419
Richard S. Hall5eda19c2008-02-29 19:52:53 +00003420 // Verify that all native libraries exist in advance; this will
3421 // throw an exception if the native library does not exist.
3422 // TODO: CACHE - It would be nice if this check could be done
3423 // some place else in the module, perhaps.
3424 R4Library[] libs = md.getLibraries();
3425 for (int i = 0; (libs != null) && (i < libs.length); i++)
3426 {
3427 String entryName = libs[i].getEntryName();
3428 if (entryName != null)
3429 {
3430 if (contentLoader.getContent().getEntryAsNativeLibrary(entryName) == null)
3431 {
3432 // The content loader was opened when trying to find the libraries,
3433 // so make sure to close it since it will be deleted.
3434 contentLoader.close();
3435 throw new BundleException("Native library does not exist: " + entryName);
3436 }
3437 }
3438 }
3439
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003440 // Done, so return the module.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003441 return module;
3442 }
3443
3444 private BundleActivator createBundleActivator(BundleInfo info)
3445 throws Exception
3446 {
3447 // CONCURRENCY NOTE:
3448 // This method is called indirectly from startBundle() (via _startBundle()),
3449 // which has the exclusion lock, so there is no need to do any locking here.
Karl Pauls836bb402006-08-24 12:39:46 +00003450
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003451 // Get the activator class from the header map.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003452 BundleActivator activator = null;
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003453 Map headerMap = info.getCurrentHeader();
3454 String className = (String) headerMap.get(Constants.BUNDLE_ACTIVATOR);
3455 // Try to instantiate activator class if present.
3456 if (className != null)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003457 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003458 className = className.trim();
3459 Class clazz;
Richard S. Hall930fecc2005-08-16 18:33:34 +00003460 try
3461 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003462 clazz = info.getCurrentModule().getClass(className);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003463 }
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003464 catch (ClassNotFoundException ex) {
3465 throw new BundleException("Not found: "
3466 + className, ex);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003467 }
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003468 activator = (BundleActivator) clazz.newInstance();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003469 }
Karl Pauls836bb402006-08-24 12:39:46 +00003470
Richard S. Hall930fecc2005-08-16 18:33:34 +00003471 return activator;
3472 }
3473
Richard S. Hall26b91982007-07-04 21:15:05 +00003474 private void purgeBundle(FelixBundle bundle) throws Exception
Richard S. Hall930fecc2005-08-16 18:33:34 +00003475 {
3476 // Acquire bundle lock.
3477 acquireBundleLock(bundle);
3478
3479 try
3480 {
3481 BundleInfo info = bundle.getInfo();
Karl Pauls836bb402006-08-24 12:39:46 +00003482
Richard S. Hall930fecc2005-08-16 18:33:34 +00003483 // In case of a refresh, then we want to physically
3484 // remove the bundle's modules from the module manager.
3485 // This is necessary for two reasons: 1) because
3486 // under Windows we won't be able to delete the bundle
3487 // because files might be left open in the resource
3488 // sources of its modules and 2) we want to make sure
3489 // that no references to old modules exist since they
3490 // will all be stale after the refresh. The only other
3491 // way to do this is to remove the bundle, but that
3492 // would be incorrect, because this is a refresh operation
3493 // and should not trigger bundle REMOVE events.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003494 IModule[] modules = info.getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003495 for (int i = 0; i < modules.length; i++)
3496 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003497 m_factory.removeModule(modules[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003498 }
3499
3500 // Purge all bundle revisions, but the current one.
Richard S. Hall7c9da3d2006-02-24 20:09:28 +00003501 m_cache.getArchive(info.getBundleId()).purge();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003502 }
3503 finally
3504 {
3505 // Always release the bundle lock.
3506 releaseBundleLock(bundle);
3507 }
3508 }
3509
Richard S. Hall26b91982007-07-04 21:15:05 +00003510 private void garbageCollectBundle(FelixBundle bundle) throws Exception
Richard S. Hall930fecc2005-08-16 18:33:34 +00003511 {
3512 // CONCURRENCY NOTE: There is no reason to lock this bundle,
3513 // because this method is only called during shutdown or a
3514 // refresh operation and these are already guarded by locks.
3515
3516 // Remove the bundle's associated modules from
3517 // the module manager.
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003518 IModule[] modules = bundle.getInfo().getModules();
Richard S. Hall930fecc2005-08-16 18:33:34 +00003519 for (int i = 0; i < modules.length; i++)
3520 {
Richard S. Hall29a4fbc2006-02-03 12:54:52 +00003521 m_factory.removeModule(modules[i]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003522 }
3523
3524 // Remove the bundle from the cache.
Karl Paulsa7e36b82008-04-13 19:09:20 +00003525 m_cache.remove(m_cache.getArchive(bundle.getBundleId()));
Richard S. Hall930fecc2005-08-16 18:33:34 +00003526 }
3527
3528 //
3529 // Event-related methods.
3530 //
3531
3532 /**
3533 * Fires bundle events.
3534 **/
3535 private void fireFrameworkEvent(
3536 int type, Bundle bundle, Throwable throwable)
3537 {
Richard S. Hall92770632006-07-24 10:18:52 +00003538 m_dispatcher.fireFrameworkEvent(new FrameworkEvent(type, bundle, throwable));
Richard S. Hall930fecc2005-08-16 18:33:34 +00003539 }
3540
3541 /**
3542 * Fires bundle events.
3543 *
3544 * @param type The type of bundle event to fire.
3545 * @param bundle The bundle associated with the event.
3546 **/
3547 private void fireBundleEvent(int type, Bundle bundle)
3548 {
Richard S. Hall92770632006-07-24 10:18:52 +00003549 m_dispatcher.fireBundleEvent(new BundleEvent(type, bundle));
Richard S. Hall930fecc2005-08-16 18:33:34 +00003550 }
3551
3552 /**
3553 * Fires service events.
3554 *
3555 * @param type The type of service event to fire.
3556 * @param ref The service reference associated with the event.
3557 **/
3558 private void fireServiceEvent(ServiceEvent event)
3559 {
Richard S. Hall92770632006-07-24 10:18:52 +00003560 m_dispatcher.fireServiceEvent(event);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003561 }
3562
3563 //
3564 // Property related methods.
3565 //
3566
3567 private void initializeFrameworkProperties()
3568 {
3569 // Standard OSGi properties.
Richard S. Hall471e3e62007-07-11 19:25:33 +00003570 m_configMutableMap.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003571 FelixConstants.FRAMEWORK_VERSION,
3572 FelixConstants.FRAMEWORK_VERSION_VALUE);
Richard S. Hall471e3e62007-07-11 19:25:33 +00003573 m_configMutableMap.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003574 FelixConstants.FRAMEWORK_VENDOR,
3575 FelixConstants.FRAMEWORK_VENDOR_VALUE);
Richard S. Hall471e3e62007-07-11 19:25:33 +00003576 m_configMutableMap.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003577 FelixConstants.FRAMEWORK_LANGUAGE,
3578 System.getProperty("user.language"));
Richard S. Hall471e3e62007-07-11 19:25:33 +00003579 m_configMutableMap.put(
Richard S. Hall930fecc2005-08-16 18:33:34 +00003580 FelixConstants.FRAMEWORK_OS_VERSION,
3581 System.getProperty("os.version"));
3582
3583 String s = null;
Richard S. Hall8d116d42006-09-01 19:23:28 +00003584 s = R4LibraryClause.normalizeOSName(System.getProperty("os.name"));
Richard S. Hall471e3e62007-07-11 19:25:33 +00003585 m_configMutableMap.put(FelixConstants.FRAMEWORK_OS_NAME, s);
Richard S. Hall8d116d42006-09-01 19:23:28 +00003586 s = R4LibraryClause.normalizeProcessor(System.getProperty("os.arch"));
Richard S. Hall471e3e62007-07-11 19:25:33 +00003587 m_configMutableMap.put(FelixConstants.FRAMEWORK_PROCESSOR, s);
3588 m_configMutableMap.put(
Richard S. Hall03ddc842006-03-09 14:50:16 +00003589 FelixConstants.FELIX_VERSION_PROPERTY, getFrameworkVersion());
Richard S. Hall930fecc2005-08-16 18:33:34 +00003590 }
3591
Richard S. Hall03ddc842006-03-09 14:50:16 +00003592 /**
3593 * Read the framework version from the property file.
3594 * @return the framework version as a string.
3595 **/
3596 private static String getFrameworkVersion()
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003597 {
3598 // The framework version property.
3599 Properties props = new Properties();
Richard S. Hall03ddc842006-03-09 14:50:16 +00003600 InputStream in = Felix.class.getResourceAsStream("Felix.properties");
Karl Pauls8da2c202007-11-25 23:08:12 +00003601 if (in != null)
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003602 {
Karl Pauls8da2c202007-11-25 23:08:12 +00003603 try
3604 {
3605 props.load(in);
3606 }
3607 catch (IOException ex)
3608 {
3609 ex.printStackTrace();
3610 }
Karl Pauls836bb402006-08-24 12:39:46 +00003611 }
3612
Richard S. Halla155e2e2006-03-09 21:20:02 +00003613 // Maven uses a '-' to separate the version qualifier,
3614 // while OSGi uses a '.', so we need to convert to a '.'
3615 StringBuffer sb =
3616 new StringBuffer(
3617 props.getProperty(
Karl Pauls8da2c202007-11-25 23:08:12 +00003618 FelixConstants.FELIX_VERSION_PROPERTY, "0.0.0"));
Richard S. Hall1615e552006-05-30 14:10:06 +00003619 if (sb.toString().indexOf("-") >= 0)
Richard S. Halla155e2e2006-03-09 21:20:02 +00003620 {
Richard S. Hall1615e552006-05-30 14:10:06 +00003621 sb.setCharAt(sb.toString().indexOf("-"), '.');
Richard S. Halla155e2e2006-03-09 21:20:02 +00003622 }
3623 return sb.toString();
Alex Karasulu5cfd2a02006-03-09 14:15:38 +00003624 }
Karl Pauls836bb402006-08-24 12:39:46 +00003625
Richard S. Hall930fecc2005-08-16 18:33:34 +00003626 //
3627 // Private utility methods.
3628 //
3629
3630 /**
3631 * Generated the next valid bundle identifier.
3632 **/
Richard S. Halle60d8782007-08-17 20:10:27 +00003633 private long loadNextId()
3634 {
3635 synchronized (m_nextIdLock)
3636 {
3637 // Read persisted next bundle identifier.
3638 InputStream is = null;
3639 BufferedReader br = null;
3640 try
3641 {
3642 File file = m_cache.getSystemBundleDataFile("bundle.id");
3643 is = m_secureAction.getFileInputStream(file);
3644 br = new BufferedReader(new InputStreamReader(is));
3645 return Long.parseLong(br.readLine());
3646 }
3647 catch (FileNotFoundException ex)
3648 {
3649 // Ignore this case because we assume that this is the
3650 // initial startup of the framework and therefore the
3651 // file does not exist yet.
3652 }
3653 catch (Exception ex)
3654 {
3655 m_logger.log(
3656 Logger.LOG_WARNING,
3657 "Unable to initialize next bundle identifier from persistent storage.",
3658 ex);
3659 }
3660 finally
3661 {
3662 try
3663 {
3664 if (br != null) br.close();
3665 if (is != null) is.close();
3666 }
3667 catch (Exception ex)
3668 {
3669 m_logger.log(
3670 Logger.LOG_WARNING,
3671 "Unable to close next bundle identifier file.",
3672 ex);
3673 }
3674 }
3675 }
3676
3677 return -1;
3678 }
3679
Richard S. Hall441c7152006-02-17 11:07:10 +00003680 private long getNextId()
Richard S. Hall930fecc2005-08-16 18:33:34 +00003681 {
Richard S. Hall441c7152006-02-17 11:07:10 +00003682 synchronized (m_nextIdLock)
3683 {
Richard S. Halle60d8782007-08-17 20:10:27 +00003684 // Save the current id.
3685 long id = m_nextId;
3686
3687 // Increment the next id.
3688 m_nextId++;
3689
3690 // Write the bundle state.
3691 OutputStream os = null;
3692 BufferedWriter bw = null;
3693 try
3694 {
3695 File file = m_cache.getSystemBundleDataFile("bundle.id");
3696 os = m_secureAction.getFileOutputStream(file);
3697 bw = new BufferedWriter(new OutputStreamWriter(os));
3698 String s = Long.toString(m_nextId);
3699 bw.write(s, 0, s.length());
3700 }
3701 catch (Exception ex)
3702 {
3703 m_logger.log(
3704 Logger.LOG_WARNING,
3705 "Unable to save next bundle identifier to persistent storage.",
3706 ex);
3707 }
3708 finally
3709 {
3710 try
3711 {
3712 if (bw != null) bw.close();
3713 if (os != null) os.close();
3714 }
3715 catch (Exception ex)
3716 {
3717 m_logger.log(
3718 Logger.LOG_WARNING,
3719 "Unable to close next bundle identifier file.",
3720 ex);
3721 }
3722 }
3723
3724 return id;
Richard S. Hall441c7152006-02-17 11:07:10 +00003725 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003726 }
3727
3728 //
Richard S. Hall26b91982007-07-04 21:15:05 +00003729 // Miscellaneous inner classes.
Richard S. Hall930fecc2005-08-16 18:33:34 +00003730 //
3731
Richard S. Hall26b91982007-07-04 21:15:05 +00003732 class SystemBundleActivator implements BundleActivator, Runnable
Richard S. Hall930fecc2005-08-16 18:33:34 +00003733 {
Richard S. Hall26b91982007-07-04 21:15:05 +00003734 public void start(BundleContext context) throws Exception
Richard S. Hall930fecc2005-08-16 18:33:34 +00003735 {
Richard S. Hall26b91982007-07-04 21:15:05 +00003736 // Add the bundle activator for the package admin service.
Richard S. Hall7adef032007-12-14 21:55:01 +00003737 m_activatorList.add(0, new PackageAdminActivator(Felix.this));
Richard S. Hall26b91982007-07-04 21:15:05 +00003738 // Add the bundle activator for the start level service.
Richard S. Hall7adef032007-12-14 21:55:01 +00003739 m_activatorList.add(0, new StartLevelActivator(m_logger, Felix.this));
Richard S. Hall26b91982007-07-04 21:15:05 +00003740 // Add the bundle activator for the url handler service.
Richard S. Hall7adef032007-12-14 21:55:01 +00003741 m_activatorList.add(0, new URLHandlersActivator(m_configMap, Felix.this));
Richard S. Hall26b91982007-07-04 21:15:05 +00003742
3743 // Start all activators.
3744 for (int i = 0; i < m_activatorList.size(); i++)
3745 {
3746 Felix.m_secureAction.startActivator(
3747 (BundleActivator) m_activatorList.get(i), context);
3748 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003749 }
3750
Richard S. Hall26b91982007-07-04 21:15:05 +00003751 public void stop(BundleContext context)
Richard S. Hall930fecc2005-08-16 18:33:34 +00003752 {
Richard S. Hall26b91982007-07-04 21:15:05 +00003753 // Spec says stop() on SystemBundle should return immediately and
3754 // shutdown framework on another thread.
3755 if (m_shutdownThread == null)
3756 {
3757 // Initial call of stop, so kick off shutdown.
3758 m_shutdownThread = new Thread(this, "FelixShutdown");
3759 m_shutdownThread.start();
3760 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003761 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003762
Richard S. Hall26b91982007-07-04 21:15:05 +00003763 public void run()
3764 {
3765 // First, start the framework shutdown, which will
3766 // stop all bundles.
Richard S. Hall675b0552007-07-23 17:03:39 +00003767 synchronized (Felix.this)
Richard S. Hall26b91982007-07-04 21:15:05 +00003768 {
3769 // Change framework state from active to stopping.
3770 // If framework is not active, then just return.
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003771 if (m_sbi.getState() != Bundle.STOPPING)
Richard S. Hall26b91982007-07-04 21:15:05 +00003772 {
3773 return;
3774 }
3775 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003776
Richard S. Hall26b91982007-07-04 21:15:05 +00003777 // Use the start level service to set the start level to zero
3778 // in order to stop all bundles in the framework. Since framework
3779 // shutdown happens on its own thread, we can wait for the start
3780 // level service to finish before proceeding by calling the
3781 // non-spec setStartLevelAndWait() method.
3782 try
3783 {
3784 StartLevelImpl sl = (StartLevelImpl) getService(
3785 Felix.this,
3786 getServiceReferences(Felix.this, StartLevel.class.getName(), null, true)[0]);
3787 sl.setStartLevelAndWait(0);
3788 }
3789 catch (InvalidSyntaxException ex)
3790 {
3791 // Should never happen.
3792 }
3793
3794 // Since there may be updated and uninstalled bundles that
3795 // have not been refreshed, we will take care of refreshing
3796 // them during shutdown.
3797
3798 // First loop through all bundled and purge old revisions
3799 // from updated bundles.
3800 Bundle[] bundles = getBundles();
3801 for (int i = 0; i < bundles.length; i++)
3802 {
3803 FelixBundle bundle = (FelixBundle) bundles[i];
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003804 BundleInfo info = bundle.getInfo();
3805 if ((info instanceof RegularBundleInfo) &&
3806 (((RegularBundleInfo) info).getArchive().getRevisionCount() > 1))
Richard S. Hall26b91982007-07-04 21:15:05 +00003807 {
3808 try
3809 {
3810 purgeBundle(bundle);
3811 }
3812 catch (Exception ex)
3813 {
3814 fireFrameworkEvent(FrameworkEvent.ERROR, bundle, ex);
3815 m_logger.log(Logger.LOG_ERROR, "Unable to purge bundle "
3816 + bundle.getInfo().getLocation(), ex);
3817 }
3818 }
3819 }
3820
3821 // Next garbage collection any uninstalled bundles.
3822 for (int i = 0;
3823 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
3824 i++)
3825 {
3826 try
3827 {
3828 garbageCollectBundle(m_uninstalledBundles[i]);
3829 }
3830 catch (Exception ex)
3831 {
3832 m_logger.log(
3833 Logger.LOG_ERROR,
3834 "Unable to remove "
3835 + m_uninstalledBundles[i].getInfo().getLocation(), ex);
3836 }
3837 }
3838
3839 // Shutdown event dispatching queue.
3840 EventDispatcher.shutdown();
3841
3842 // Remove all bundles from the module factory so that any
3843 // open resources will be closed.
3844 bundles = getBundles();
3845 for (int i = 0; i < bundles.length; i++)
3846 {
3847 FelixBundle bundle = (FelixBundle) bundles[i];
3848 IModule[] modules = bundle.getInfo().getModules();
3849 for (int j = 0; j < modules.length; j++)
3850 {
3851 try
3852 {
3853 m_factory.removeModule(modules[j]);
3854 }
3855 catch (Exception ex)
3856 {
3857 m_logger.log(Logger.LOG_ERROR,
3858 "Unable to clean up " + bundle.getInfo().getLocation(), ex);
3859 }
3860 }
3861 }
3862
3863 // Next, stop all system bundle activators.
Karl Pauls758c2be2008-03-05 13:10:04 +00003864 for (int i = 0; i < m_activatorList.size(); i++)
Richard S. Hall26b91982007-07-04 21:15:05 +00003865 {
Karl Pauls758c2be2008-03-05 13:10:04 +00003866 try
Richard S. Hall26b91982007-07-04 21:15:05 +00003867 {
Richard S. Hall2846a2b2008-06-01 03:08:17 +00003868 Felix.m_secureAction.stopActivator((BundleActivator)
Karl Pauls758c2be2008-03-05 13:10:04 +00003869 m_activatorList.get(i), getInfo().getBundleContext());
3870 }
3871 catch (Throwable throwable)
3872 {
3873 m_logger.log(
3874 Logger.LOG_WARNING,
3875 "Exception stopping a system bundle activator.",
3876 throwable);
Richard S. Hall26b91982007-07-04 21:15:05 +00003877 }
3878 }
3879
3880 if (m_extensionManager != null)
3881 {
3882 m_extensionManager.removeExtensions(Felix.this);
3883 }
3884
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003885 // Set the framework state to resolved.
Richard S. Hall675b0552007-07-23 17:03:39 +00003886 synchronized (Felix.this)
Richard S. Hall26b91982007-07-04 21:15:05 +00003887 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003888 m_sbi.setState(Bundle.RESOLVED);
3889 m_shutdownGate.open();
3890 m_shutdownGate = null;
3891 m_shutdownThread = null;
Richard S. Hall26b91982007-07-04 21:15:05 +00003892 }
3893 }
Richard S. Hall930fecc2005-08-16 18:33:34 +00003894 }
3895
3896 /**
3897 * Simple class that is used in <tt>refreshPackages()</tt> to embody
3898 * the refresh logic in order to keep the code clean. This class is
3899 * not static because it needs access to framework event firing methods.
3900 **/
3901 private class RefreshHelper
3902 {
Richard S. Hall26b91982007-07-04 21:15:05 +00003903 private FelixBundle m_bundle = null;
Richard S. Hall06862742008-09-29 17:37:19 +00003904 private int m_oldState = Bundle.INSTALLED;
Richard S. Hall930fecc2005-08-16 18:33:34 +00003905
3906 public RefreshHelper(Bundle bundle)
3907 {
Richard S. Hall26b91982007-07-04 21:15:05 +00003908 m_bundle = (FelixBundle) bundle;
Richard S. Hall930fecc2005-08-16 18:33:34 +00003909 }
3910
3911 public void stop()
3912 {
3913 if (m_bundle.getInfo().getState() == Bundle.ACTIVE)
3914 {
Richard S. Hall06862742008-09-29 17:37:19 +00003915 m_oldState = Bundle.ACTIVE;
Richard S. Hall930fecc2005-08-16 18:33:34 +00003916 try
3917 {
3918 stopBundle(m_bundle, false);
3919 }
3920 catch (BundleException ex)
3921 {
3922 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3923 }
3924 }
3925 }
3926
3927 public void purgeOrRemove()
3928 {
3929 try
3930 {
3931 BundleInfo info = m_bundle.getInfo();
3932
Richard S. Halle1f53a52006-07-17 11:06:59 +00003933 // Mark the bundle as stale.
3934 info.setStale();
3935
Richard S. Hall930fecc2005-08-16 18:33:34 +00003936 // Remove or purge the bundle depending on its
3937 // current state.
3938 if (info.getState() == Bundle.UNINSTALLED)
3939 {
3940 // This physically removes the bundle from memory
3941 // as well as the bundle cache.
3942 garbageCollectBundle(m_bundle);
3943 m_bundle = null;
3944 }
3945 else
3946 {
3947 // This physically removes all old revisions of the
3948 // bundle from memory and only maintains the newest
3949 // version in the bundle cache.
3950 purgeBundle(m_bundle);
3951 }
3952 }
3953 catch (Exception ex)
3954 {
3955 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3956 }
3957 }
3958
3959 public void reinitialize()
3960 {
3961 if (m_bundle != null)
3962 {
3963 try
3964 {
Richard S. Hallafb4ab42008-10-08 21:18:29 +00003965 RegularBundleInfo info = (RegularBundleInfo) m_bundle.getInfo();
3966 RegularBundleInfo newInfo = createBundleInfo(
Richard S. Hall219b0a22008-09-05 21:38:05 +00003967 info.getArchive(), info.getCurrentHeader(), info.isExtension());
Richard S. Hall930fecc2005-08-16 18:33:34 +00003968 newInfo.syncLock(info);
Richard S. Hall26b91982007-07-04 21:15:05 +00003969 ((BundleImpl) m_bundle).setInfo(newInfo);
Karl Pauls28636dc2008-02-03 21:32:48 +00003970 addSecurity(m_bundle);
Richard S. Hall2dea05f2006-07-25 10:18:20 +00003971 fireBundleEvent(BundleEvent.UNRESOLVED, m_bundle);
Richard S. Hall930fecc2005-08-16 18:33:34 +00003972 }
3973 catch (Exception ex)
3974 {
3975 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3976 }
3977 }
3978 }
3979
3980 public void restart()
3981 {
Richard S. Hall06862742008-09-29 17:37:19 +00003982 if ((m_bundle != null) && (m_oldState == Bundle.ACTIVE))
Richard S. Hall930fecc2005-08-16 18:33:34 +00003983 {
3984 try
3985 {
3986 startBundle(m_bundle, false);
3987 }
3988 catch (BundleException ex)
3989 {
3990 fireFrameworkEvent(FrameworkEvent.ERROR, m_bundle, ex);
3991 }
3992 }
3993 }
3994 }
3995
3996 //
3997 // Locking related methods.
3998 //
3999
Richard S. Hall26b91982007-07-04 21:15:05 +00004000 private void rememberUninstalledBundle(FelixBundle bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00004001 {
4002 synchronized (m_uninstalledBundlesLock_Priority3)
4003 {
4004 // Verify that the bundle is not already in the array.
4005 for (int i = 0;
4006 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
4007 i++)
4008 {
4009 if (m_uninstalledBundles[i] == bundle)
4010 {
4011 return;
4012 }
4013 }
4014
4015 if (m_uninstalledBundles != null)
4016 {
Richard S. Hall26b91982007-07-04 21:15:05 +00004017 FelixBundle[] newBundles =
4018 new FelixBundle[m_uninstalledBundles.length + 1];
Richard S. Hall930fecc2005-08-16 18:33:34 +00004019 System.arraycopy(m_uninstalledBundles, 0,
4020 newBundles, 0, m_uninstalledBundles.length);
4021 newBundles[m_uninstalledBundles.length] = bundle;
4022 m_uninstalledBundles = newBundles;
4023 }
4024 else
4025 {
Richard S. Hall26b91982007-07-04 21:15:05 +00004026 m_uninstalledBundles = new FelixBundle[] { bundle };
Richard S. Hall930fecc2005-08-16 18:33:34 +00004027 }
4028 }
4029 }
4030
Richard S. Hall26b91982007-07-04 21:15:05 +00004031 private void forgetUninstalledBundle(FelixBundle bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00004032 {
4033 synchronized (m_uninstalledBundlesLock_Priority3)
4034 {
4035 if (m_uninstalledBundles == null)
4036 {
4037 return;
4038 }
Karl Pauls836bb402006-08-24 12:39:46 +00004039
Richard S. Hall930fecc2005-08-16 18:33:34 +00004040 int idx = -1;
4041 for (int i = 0; i < m_uninstalledBundles.length; i++)
4042 {
4043 if (m_uninstalledBundles[i] == bundle)
4044 {
4045 idx = i;
4046 break;
4047 }
4048 }
Karl Pauls836bb402006-08-24 12:39:46 +00004049
Richard S. Hall930fecc2005-08-16 18:33:34 +00004050 if (idx >= 0)
4051 {
4052 // If this is the only bundle, then point to empty list.
4053 if ((m_uninstalledBundles.length - 1) == 0)
4054 {
Richard S. Hall26b91982007-07-04 21:15:05 +00004055 m_uninstalledBundles = new FelixBundle[0];
Richard S. Hall930fecc2005-08-16 18:33:34 +00004056 }
4057 // Otherwise, we need to do some array copying.
4058 else
4059 {
Richard S. Hall26b91982007-07-04 21:15:05 +00004060 FelixBundle[] newBundles =
4061 new FelixBundle[m_uninstalledBundles.length - 1];
Richard S. Hall930fecc2005-08-16 18:33:34 +00004062 System.arraycopy(m_uninstalledBundles, 0, newBundles, 0, idx);
4063 if (idx < newBundles.length)
4064 {
4065 System.arraycopy(
4066 m_uninstalledBundles, idx + 1,
4067 newBundles, idx, newBundles.length - idx);
4068 }
4069 m_uninstalledBundles = newBundles;
4070 }
4071 }
4072 }
4073 }
4074
4075 protected void acquireInstallLock(String location)
4076 throws BundleException
4077 {
4078 synchronized (m_installRequestLock_Priority1)
4079 {
4080 while (m_installRequestMap.get(location) != null)
4081 {
4082 try
4083 {
4084 m_installRequestLock_Priority1.wait();
4085 }
4086 catch (InterruptedException ex)
4087 {
4088 throw new BundleException("Unable to install, thread interrupted.");
4089 }
4090 }
Karl Pauls836bb402006-08-24 12:39:46 +00004091
Richard S. Hall930fecc2005-08-16 18:33:34 +00004092 m_installRequestMap.put(location, location);
4093 }
4094 }
Karl Pauls836bb402006-08-24 12:39:46 +00004095
Richard S. Hall930fecc2005-08-16 18:33:34 +00004096 protected void releaseInstallLock(String location)
4097 {
4098 synchronized (m_installRequestLock_Priority1)
4099 {
4100 m_installRequestMap.remove(location);
4101 m_installRequestLock_Priority1.notifyAll();
4102 }
4103 }
4104
Richard S. Hall26b91982007-07-04 21:15:05 +00004105 protected void acquireBundleLock(FelixBundle bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00004106 {
4107 synchronized (m_bundleLock)
4108 {
4109 while (!bundle.getInfo().isLockable())
4110 {
4111 try
4112 {
4113 m_bundleLock.wait();
4114 }
4115 catch (InterruptedException ex)
4116 {
4117 // Ignore and just keep waiting.
4118 }
4119 }
4120 bundle.getInfo().lock();
4121 }
4122 }
Karl Pauls836bb402006-08-24 12:39:46 +00004123
Richard S. Hall26b91982007-07-04 21:15:05 +00004124 protected boolean acquireBundleLockOrFail(FelixBundle bundle)
Richard S. Hall3c26cc02006-02-17 13:51:21 +00004125 {
4126 synchronized (m_bundleLock)
4127 {
4128 if (!bundle.getInfo().isLockable())
4129 {
4130 return false;
4131 }
4132 bundle.getInfo().lock();
4133 return true;
4134 }
4135 }
4136
Richard S. Hall26b91982007-07-04 21:15:05 +00004137 protected void releaseBundleLock(FelixBundle bundle)
Richard S. Hall930fecc2005-08-16 18:33:34 +00004138 {
4139 synchronized (m_bundleLock)
4140 {
4141 bundle.getInfo().unlock();
4142 m_bundleLock.notifyAll();
4143 }
4144 }
4145
Richard S. Hall26b91982007-07-04 21:15:05 +00004146 protected FelixBundle[] acquireBundleResolveLocks(Bundle[] targets)
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004147 {
4148 // Hold bundles to be locked.
Richard S. Hall26b91982007-07-04 21:15:05 +00004149 FelixBundle[] bundles = null;
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004150 // Convert existing target bundle array to bundle impl array.
4151 if (targets != null)
4152 {
Richard S. Hall26b91982007-07-04 21:15:05 +00004153 bundles = new FelixBundle[targets.length];
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004154 for (int i = 0; i < targets.length; i++)
4155 {
Richard S. Hall26b91982007-07-04 21:15:05 +00004156 bundles[i] = (FelixBundle) targets[i];
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004157 }
4158 }
4159
4160 synchronized (m_bundleLock)
4161 {
4162 boolean success = false;
4163 while (!success)
4164 {
4165 // If targets is null, then resolve all unresolved bundles.
4166 if (targets == null)
4167 {
4168 List list = new ArrayList();
4169
4170 // Add all unresolved bundles to the list.
4171 synchronized (m_installedBundleLock_Priority2)
4172 {
4173 Iterator iter = m_installedBundleMap.values().iterator();
4174 while (iter.hasNext())
4175 {
Richard S. Hall26b91982007-07-04 21:15:05 +00004176 FelixBundle bundle = (FelixBundle) iter.next();
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004177 if (bundle.getInfo().getState() == Bundle.INSTALLED)
4178 {
4179 list.add(bundle);
4180 }
4181 }
4182 }
4183
4184 // Create an array.
4185 if (list.size() > 0)
4186 {
Richard S. Hall26b91982007-07-04 21:15:05 +00004187 bundles = (FelixBundle[]) list.toArray(new FelixBundle[list.size()]);
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004188 }
4189 }
Karl Pauls836bb402006-08-24 12:39:46 +00004190
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004191 // Check if all unresolved bundles can be locked.
4192 boolean lockable = true;
4193 if (bundles != null)
4194 {
4195 for (int i = 0; lockable && (i < bundles.length); i++)
4196 {
4197 lockable = bundles[i].getInfo().isLockable();
4198 }
Karl Pauls836bb402006-08-24 12:39:46 +00004199
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004200 // If we can lock all bundles, then lock them.
4201 if (lockable)
4202 {
4203 for (int i = 0; i < bundles.length; i++)
4204 {
4205 bundles[i].getInfo().lock();
4206 }
4207 success = true;
4208 }
4209 // Otherwise, wait and try again.
4210 else
4211 {
4212 try
4213 {
4214 m_bundleLock.wait();
4215 }
4216 catch (InterruptedException ex)
4217 {
4218 // Ignore and just keep waiting.
4219 }
4220 }
4221 }
4222 else
4223 {
4224 // If there were no bundles to lock, then we can just
4225 // exit the lock loop.
4226 success = true;
4227 }
4228 }
4229 }
4230
4231 return bundles;
4232 }
4233
Richard S. Hall26b91982007-07-04 21:15:05 +00004234 protected FelixBundle[] acquireBundleRefreshLocks(Bundle[] targets)
Richard S. Hall930fecc2005-08-16 18:33:34 +00004235 {
4236 // Hold bundles to be locked.
Richard S. Hall26b91982007-07-04 21:15:05 +00004237 FelixBundle[] bundles = null;
Richard S. Hall930fecc2005-08-16 18:33:34 +00004238
4239 synchronized (m_bundleLock)
4240 {
4241 boolean success = false;
4242 while (!success)
4243 {
4244 // If targets is null, then refresh all pending bundles.
4245 Bundle[] newTargets = targets;
4246 if (newTargets == null)
4247 {
4248 List list = new ArrayList();
4249
4250 // First add all uninstalled bundles.
4251 synchronized (m_uninstalledBundlesLock_Priority3)
4252 {
4253 for (int i = 0;
4254 (m_uninstalledBundles != null) && (i < m_uninstalledBundles.length);
4255 i++)
4256 {
4257 list.add(m_uninstalledBundles[i]);
4258 }
4259 }
4260
4261 // Then add all updated bundles.
4262 synchronized (m_installedBundleLock_Priority2)
4263 {
4264 Iterator iter = m_installedBundleMap.values().iterator();
4265 while (iter.hasNext())
4266 {
Richard S. Hall26b91982007-07-04 21:15:05 +00004267 FelixBundle bundle = (FelixBundle) iter.next();
Richard S. Hallafb4ab42008-10-08 21:18:29 +00004268 BundleInfo info = bundle.getInfo();
4269 if ((info instanceof RegularBundleInfo) &&
4270 (((RegularBundleInfo) info).getArchive().getRevisionCount() > 1))
Richard S. Hall930fecc2005-08-16 18:33:34 +00004271 {
4272 list.add(bundle);
4273 }
4274 }
4275 }
4276
4277 // Create an array.
4278 if (list.size() > 0)
4279 {
4280 newTargets = (Bundle[]) list.toArray(new Bundle[list.size()]);
4281 }
4282 }
4283
4284 // If there are targets, then find all dependencies
4285 // for each one.
4286 if (newTargets != null)
4287 {
4288 // Create map of bundles that import the packages
4289 // from the target bundles.
4290 Map map = new HashMap();
4291 for (int targetIdx = 0; targetIdx < newTargets.length; targetIdx++)
4292 {
4293 // Add the current target bundle to the map of
4294 // bundles to be refreshed.
Richard S. Hall26b91982007-07-04 21:15:05 +00004295 FelixBundle target = (FelixBundle) newTargets[targetIdx];
Richard S. Hall930fecc2005-08-16 18:33:34 +00004296 map.put(target, target);
4297 // Add all importing bundles to map.
4298 populateImportGraph(target, map);
4299 }
Karl Pauls836bb402006-08-24 12:39:46 +00004300
Richard S. Hall26b91982007-07-04 21:15:05 +00004301 bundles = (FelixBundle[]) map.values().toArray(new FelixBundle[map.size()]);
Richard S. Hall930fecc2005-08-16 18:33:34 +00004302 }
Karl Pauls836bb402006-08-24 12:39:46 +00004303
Richard S. Hall1a4ab602006-05-24 13:46:06 +00004304 // Check if all corresponding bundles can be locked.
Richard S. Hall930fecc2005-08-16 18:33:34 +00004305 boolean lockable = true;
4306 if (bundles != null)
4307 {
4308 for (int i = 0; lockable && (i < bundles.length); i++)
4309 {
4310 lockable = bundles[i].getInfo().isLockable();
4311 }
Karl Pauls836bb402006-08-24 12:39:46 +00004312
Richard S. Hall930fecc2005-08-16 18:33:34 +00004313 // If we can lock all bundles, then lock them.
4314 if (lockable)
4315 {
4316 for (int i = 0; i < bundles.length; i++)
4317 {
4318 bundles[i].getInfo().lock();
4319 }
4320 success = true;
4321 }
4322 // Otherwise, wait and try again.
4323 else
4324 {
4325 try
4326 {
4327 m_bundleLock.wait();
4328 }
4329 catch (InterruptedException ex)
4330 {
4331 // Ignore and just keep waiting.
4332 }
4333 }
4334 }
4335 else
4336 {
4337 // If there were no bundles to lock, then we can just
4338 // exit the lock loop.
4339 success = true;
4340 }
4341 }
4342 }
4343
4344 return bundles;
4345 }
4346
Richard S. Hall26b91982007-07-04 21:15:05 +00004347 protected void releaseBundleLocks(FelixBundle[] bundles)
Richard S. Hall930fecc2005-08-16 18:33:34 +00004348 {
4349 // Always unlock any locked bundles.
4350 synchronized (m_bundleLock)
4351 {
4352 for (int i = 0; (bundles != null) && (i < bundles.length); i++)
4353 {
4354 bundles[i].getInfo().unlock();
4355 }
4356 m_bundleLock.notifyAll();
4357 }
4358 }
Richard S. Hall12bbff62008-10-10 14:30:42 +00004359}