use of org.apache.felix.framework.cache.BundleArchive in project felix by apache.
the class Felix method installBundle.
Bundle installBundle(Bundle origin, String location, InputStream is) throws BundleException {
BundleArchive ba = null;
BundleImpl existing, bundle = null;
// Acquire an install lock.
acquireInstallLock(location);
try {
// Check to see if the framework is still running;
if ((getState() == Bundle.STOPPING) || (getState() == Bundle.UNINSTALLED)) {
throw new BundleException("The framework has been shutdown.");
}
// If bundle location is already installed, then
// return it as required by the OSGi specification.
existing = (BundleImpl) getBundle(location);
if (existing == null) {
// First generate an identifier for it.
long id = getNextId();
try {
// Add the bundle to the cache.
ba = m_cache.create(id, getInitialBundleStartLevel(), location, is);
} catch (Exception ex) {
throw new BundleException("Unable to cache bundle: " + location, ex);
} finally {
try {
if (is != null)
is.close();
} catch (IOException ex) {
m_logger.log(Logger.LOG_ERROR, "Unable to close input stream.", ex);
}
}
try {
// Acquire the global lock to create the bundle,
// since this impacts the global state.
boolean locked = acquireGlobalLock();
if (!locked) {
throw new BundleException("Unable to acquire the global lock to install the bundle.");
}
try {
bundle = new BundleImpl(this, origin, ba);
} finally {
// Always release the global lock.
releaseGlobalLock();
}
if (!bundle.isExtension()) {
Object sm = System.getSecurityManager();
if (sm != null) {
((SecurityManager) sm).checkPermission(new AdminPermission(bundle, AdminPermission.LIFECYCLE));
}
} else {
m_extensionManager.addExtensionBundle(this, bundle);
}
} catch (Throwable ex) {
// Remove bundle from the cache.
try {
if (bundle != null) {
bundle.closeAndDelete();
} else if (ba != null) {
ba.closeAndDelete();
}
} catch (Exception ex1) {
m_logger.log(bundle, Logger.LOG_ERROR, "Could not remove from cache.", ex1);
}
if (ex instanceof BundleException) {
throw (BundleException) ex;
} else if (ex instanceof AccessControlException) {
throw (AccessControlException) ex;
} else {
throw new BundleException("Could not create bundle object.", ex);
}
}
// Acquire global lock.
boolean locked = acquireGlobalLock();
if (!locked) {
// be able to get the global lock.
throw new IllegalStateException("Unable to acquire global lock to add bundle.");
}
try {
// Use a copy-on-write approach to add the bundle
// to the installed maps.
Map[] maps = new Map[] { new HashMap<String, BundleImpl>(m_installedBundles[LOCATION_MAP_IDX]), new TreeMap<Long, BundleImpl>(m_installedBundles[IDENTIFIER_MAP_IDX]) };
maps[LOCATION_MAP_IDX].put(location, bundle);
maps[IDENTIFIER_MAP_IDX].put(new Long(bundle.getBundleId()), bundle);
m_installedBundles = maps;
} finally {
releaseGlobalLock();
}
for (Bundle extension : m_extensionManager.resolveExtensionBundles(this)) {
m_extensionManager.startExtensionBundle(this, (BundleImpl) extension);
}
}
} finally {
// Always release install lock.
releaseInstallLock(location);
// Always try to close the input stream.
try {
if (is != null)
is.close();
} catch (IOException ex) {
m_logger.log(bundle, Logger.LOG_ERROR, "Unable to close input stream.", ex);
// Not much else we can do.
}
}
if (existing != null) {
Set<ServiceReference<org.osgi.framework.hooks.bundle.FindHook>> hooks = getHookRegistry().getHooks(org.osgi.framework.hooks.bundle.FindHook.class);
if (!hooks.isEmpty()) {
Collection<Bundle> bundles = new ArrayList<Bundle>(1);
bundles.add(existing);
bundles = new ShrinkableCollection<Bundle>(bundles);
for (ServiceReference<org.osgi.framework.hooks.bundle.FindHook> hook : hooks) {
org.osgi.framework.hooks.bundle.FindHook fh = getService(this, hook, false);
if (fh != null) {
try {
m_secureAction.invokeBundleFindHook(fh, ((BundleImpl) origin)._getBundleContext(), bundles);
} catch (Throwable th) {
m_logger.doLog(hook.getBundle(), hook, Logger.LOG_WARNING, "Problem invoking bundle hook.", th);
}
}
}
if (origin != this) {
// trying to prevent it.
if (bundles.isEmpty()) {
throw new BundleException("Bundle installation rejected by hook.", BundleException.REJECTED_BY_HOOK);
}
}
}
} else {
// Fire bundle event.
fireBundleEvent(BundleEvent.INSTALLED, bundle, origin);
}
// Return new bundle.
return (existing != null) ? existing : bundle;
}
use of org.apache.felix.framework.cache.BundleArchive in project felix by apache.
the class Felix method init.
/**
* @see org.osgi.framework.launch.Framework#init(org.osgi.framework.FrameworkListener[])
*/
@Override
public void init(final FrameworkListener... listeners) throws BundleException {
// The system bundle can only be initialized if it currently isn't started.
acquireBundleLock(this, Bundle.INSTALLED | Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE);
try {
if ((getState() == Bundle.INSTALLED) || (getState() == Bundle.RESOLVED)) {
String security = (String) m_configMap.get(Constants.FRAMEWORK_SECURITY);
if (security != null) {
if (System.getSecurityManager() != null) {
throw new SecurityException("SecurityManager already installed");
}
security = security.trim();
if (Constants.FRAMEWORK_SECURITY_OSGI.equalsIgnoreCase(security) || (security.length() == 0)) {
System.setSecurityManager(m_securityManager = new SecurityManager());
} else {
try {
System.setSecurityManager(m_securityManager = (SecurityManager) Class.forName(security).newInstance());
} catch (Throwable t) {
SecurityException se = new SecurityException("Unable to install custom SecurityManager: " + security);
se.initCause(t);
throw se;
}
}
}
// Generate a framework UUID.
// Spec says we get a new UUID for each invocation of init().
m_configMutableMap.put(FelixConstants.FRAMEWORK_UUID, Util.randomUUID());
// Initialize event dispatcher.
m_dispatcher.startDispatching();
// Create the bundle cache, if necessary, so that we can reload any
// installed bundles.
m_cache = (BundleCache) m_configMutableMap.get(FelixConstants.FRAMEWORK_BUNDLECACHE_IMPL);
if (m_cache == null) {
try {
m_cache = new BundleCache(m_logger, m_configMap);
} catch (Exception ex) {
m_logger.log(Logger.LOG_ERROR, "Error creating bundle cache.", ex);
throw new BundleException("Error creating bundle cache.", ex);
}
}
// we need to flush the bundle cache.
if (getState() == Bundle.INSTALLED) {
String clean = (String) m_configMap.get(Constants.FRAMEWORK_STORAGE_CLEAN);
if ((clean != null) && clean.equalsIgnoreCase(Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT)) {
try {
m_cache.delete();
} catch (Exception ex) {
throw new BundleException("Unable to flush bundle cache.", ex);
}
}
}
// Initialize installed bundle data structures.
Map[] maps = new Map[] { new HashMap<String, BundleImpl>(1), new TreeMap<Long, BundleImpl>() };
m_uninstalledBundles = new ArrayList<BundleImpl>(0);
// Add the system bundle to the set of installed bundles.
maps[LOCATION_MAP_IDX].put(_getLocation(), this);
maps[IDENTIFIER_MAP_IDX].put(new Long(0), this);
m_installedBundles = maps;
// state to be set to RESOLVED.
try {
m_resolver.resolve(Collections.singleton(adapt(BundleRevision.class)), Collections.EMPTY_SET);
} catch (ResolutionException ex) {
// This should never happen.
throw new BundleException("Unresolved constraint in System Bundle:" + ex.getUnresolvedRequirements());
}
// Reload the cached bundles before creating and starting the
// system bundle, since we want all cached bundles to be reloaded
// when we activate the system bundle and any subsequent system
// bundle activators passed into the framework constructor.
BundleArchive[] archives = null;
// First get cached bundle identifiers.
try {
archives = m_cache.getArchives();
} catch (Exception ex) {
m_logger.log(Logger.LOG_ERROR, "Unable to list saved bundles.", ex);
archives = null;
}
// Create system bundle activator and bundle context so we can activate it.
setActivator(new SystemBundleActivator());
setBundleContext(new BundleContextImpl(m_logger, this, this));
boolean javaVersionChanged = handleJavaVersionChange();
// Now load all cached bundles.
for (int i = 0; (archives != null) && (i < archives.length); i++) {
try {
// Keep track of the max bundle ID currently in use since we
// will need to use this as our next bundle ID value if the
// persisted value cannot be read.
m_nextId = Math.max(m_nextId, archives[i].getId() + 1);
// it now.
if (archives[i].getPersistentState() == Bundle.UNINSTALLED) {
archives[i].closeAndDelete();
} else // Otherwise re-install the cached bundle.
{
// Install the cached bundle.
reloadBundle(archives[i], javaVersionChanged);
}
} catch (Exception ex) {
fireFrameworkEvent(FrameworkEvent.ERROR, this, ex);
try {
m_logger.log(Logger.LOG_ERROR, "Unable to re-install " + archives[i].getLocation(), ex);
} catch (Exception ex2) {
m_logger.log(Logger.LOG_ERROR, "Unable to re-install cached bundle.", ex);
}
// TODO: FRAMEWORK - Perhaps we should remove the cached bundle?
}
}
for (Bundle extension : m_extensionManager.resolveExtensionBundles(this)) {
m_extensionManager.startExtensionBundle(this, (BundleImpl) extension);
}
// Now that we have loaded all cached bundles and have determined the
// max bundle ID of cached bundles, we need to try to load the next
// bundle ID from persistent storage. In case of failure, we should
// keep the max value.
m_nextId = Math.max(m_nextId, loadNextId());
// The framework is now in its startup sequence.
setBundleStateAndNotify(this, Bundle.STARTING);
// Now it is possible for threads to wait for the framework to stop,
// so create a gate for that purpose.
m_shutdownGate = new ThreadGate();
// add framework listeners
if (listeners != null) {
for (final FrameworkListener fl : listeners) {
addFrameworkListener(this, fl);
}
}
// Start services
m_resolver.start();
m_fwkWiring.start();
m_fwkStartLevel.start();
try {
Felix.m_secureAction.startActivator(getActivator(), _getBundleContext());
} catch (Throwable ex) {
m_dispatcher.stopDispatching();
m_logger.log(Logger.LOG_ERROR, "Unable to start system bundle.", ex);
throw new RuntimeException("Unable to start system bundle.");
}
// We have to check with the security provider (if there is one).
// This is to avoid having bundles in the cache that have been tampered with
SecurityProvider sp = getFramework().getSecurityProvider();
if ((sp != null) && (System.getSecurityManager() != null)) {
boolean locked = acquireGlobalLock();
if (!locked) {
throw new BundleException("Unable to acquire the global lock to check the bundle.");
}
try {
for (Object bundle : m_installedBundles[IDENTIFIER_MAP_IDX].values()) {
try {
if (bundle != this) {
setBundleProtectionDomain(((BundleImpl) bundle).adapt(BundleRevisionImpl.class));
}
} catch (Exception ex) {
((BundleImpl) bundle).close();
maps = new Map[] { new HashMap<String, BundleImpl>(m_installedBundles[LOCATION_MAP_IDX]), new TreeMap<Long, BundleImpl>(m_installedBundles[IDENTIFIER_MAP_IDX]) };
maps[LOCATION_MAP_IDX].remove(((BundleImpl) bundle)._getLocation());
maps[IDENTIFIER_MAP_IDX].remove(new Long(((BundleImpl) bundle).getBundleId()));
m_installedBundles = maps;
m_logger.log(Logger.LOG_ERROR, "Bundle in cache doesn't pass security check anymore.", ex);
}
}
} finally {
// Always release the global lock.
releaseGlobalLock();
}
}
m_extensionManager.startPendingExtensionBundles(Felix.this);
m_fwkWiring.refreshBundles(null);
// up class lookup for the system bundle.
synchronized (m_systemBundleClassCache) {
m_systemBundleClassCache.clear();
}
}
} finally {
releaseBundleLock(this);
if (listeners != null) {
for (final FrameworkListener fl : listeners) {
removeFrameworkListener(this, fl);
}
}
}
}
use of org.apache.felix.framework.cache.BundleArchive in project felix by apache.
the class CollisionHookTest method testCollisionHookInstall.
public void testCollisionHookInstall() throws Exception {
BundleImpl identicalBundle = mockBundleImpl(1L, "foo", "1.2.1.a");
BundleImpl differentBundle = mockBundleImpl(2L, "bar", "1.2.1.a");
BundleImpl originatingBundle = mockBundleImpl(4L, "xyz", "1.0.0");
CollisionHook testCollisionHook = new CollisionHook() {
@Override
public void filterCollisions(int operationType, Bundle target, Collection<Bundle> collisionCandidates) {
if ((target.getBundleId() == 4L) && (operationType == CollisionHook.INSTALLING)) {
collisionCandidates.clear();
}
}
};
@SuppressWarnings("unchecked") ServiceReference<CollisionHook> chRef = Mockito.mock(ServiceReference.class);
// Mock the framework
StatefulResolver mockResolver = Mockito.mock(StatefulResolver.class);
Felix felixMock = Mockito.mock(Felix.class);
HookRegistry hReg = mock(HookRegistry.class);
when(hReg.getHooks(CollisionHook.class)).thenReturn(Collections.singleton(chRef));
when(felixMock.getHookRegistry()).thenReturn(hReg);
Mockito.when(felixMock.getResolver()).thenReturn(mockResolver);
Mockito.when(felixMock.getBundles()).thenReturn(new Bundle[] { differentBundle, identicalBundle });
Mockito.when(felixMock.getService(felixMock, chRef, false)).thenReturn(testCollisionHook);
// Mock the archive of the bundle being installed
Map<String, Object> headerMap = new HashMap<String, Object>();
headerMap.put(Constants.BUNDLE_SYMBOLICNAME, "foo");
headerMap.put(Constants.BUNDLE_VERSION, "1.2.1.a");
headerMap.put(Constants.BUNDLE_MANIFESTVERSION, "2");
BundleArchiveRevision archiveRevision = Mockito.mock(BundleArchiveRevision.class);
Mockito.when(archiveRevision.getManifestHeader()).thenReturn(headerMap);
BundleArchive archive = Mockito.mock(BundleArchive.class);
Mockito.when(archive.getCurrentRevision()).thenReturn(archiveRevision);
Mockito.when(archive.getId()).thenReturn(3L);
BundleImpl bi = new BundleImpl(felixMock, originatingBundle, archive);
assertEquals(3L, bi.getBundleId());
// Do the revise operation.
try {
bi.revise(null, null);
fail("Should have thrown a BundleException because the installed bundle is not unique");
} catch (BundleException be) {
// good
assertTrue(be.getMessage().contains("not unique"));
}
}
use of org.apache.felix.framework.cache.BundleArchive in project felix by apache.
the class CollisionHookTest method testCollisionNotEnabled.
public void testCollisionNotEnabled() throws Exception {
BundleImpl identicalBundle = mockBundleImpl(1L, "foo", "1.2.1.a");
BundleImpl differentBundle = mockBundleImpl(2L, "bar", "1.2.1.a");
CollisionHook testCollisionHook = new CollisionHook() {
@Override
public void filterCollisions(int operationType, Bundle target, Collection<Bundle> collisionCandidates) {
if ((target.getBundleId() == 3L) && (operationType == CollisionHook.INSTALLING)) {
collisionCandidates.clear();
}
}
};
@SuppressWarnings("unchecked") ServiceReference<CollisionHook> chRef = Mockito.mock(ServiceReference.class);
Map<String, Object> config = new HashMap<String, Object>();
config.put(Constants.FRAMEWORK_BSNVERSION, Constants.FRAMEWORK_BSNVERSION_SINGLE);
// Mock the framework
StatefulResolver mockResolver = Mockito.mock(StatefulResolver.class);
Felix felixMock = Mockito.mock(Felix.class);
Mockito.when(felixMock.getConfig()).thenReturn(config);
HookRegistry hReg = mock(HookRegistry.class);
when(hReg.getHooks(CollisionHook.class)).thenReturn(Collections.singleton(chRef));
when(felixMock.getHookRegistry()).thenReturn(hReg);
Mockito.when(felixMock.getResolver()).thenReturn(mockResolver);
Mockito.when(felixMock.getBundles()).thenReturn(new Bundle[] { differentBundle, identicalBundle });
Mockito.when(felixMock.getService(felixMock, chRef, false)).thenReturn(testCollisionHook);
// Mock the archive of the bundle being installed
Map<String, Object> headerMap = new HashMap<String, Object>();
headerMap.put(Constants.BUNDLE_SYMBOLICNAME, "foo");
headerMap.put(Constants.BUNDLE_VERSION, "1.2.1.a");
headerMap.put(Constants.BUNDLE_MANIFESTVERSION, "2");
BundleArchiveRevision archiveRevision = Mockito.mock(BundleArchiveRevision.class);
Mockito.when(archiveRevision.getManifestHeader()).thenReturn(headerMap);
BundleArchive archive = Mockito.mock(BundleArchive.class);
Mockito.when(archive.getCurrentRevision()).thenReturn(archiveRevision);
Mockito.when(archive.getId()).thenReturn(3L);
try {
new BundleImpl(felixMock, null, archive);
fail("Should have thrown a BundleException because the collision hook is not enabled");
} catch (BundleException be) {
// good
assertTrue(be.getMessage().contains("not unique"));
}
}
use of org.apache.felix.framework.cache.BundleArchive in project felix by apache.
the class CollisionHookTest method testCollisionHookUpdate.
public void testCollisionHookUpdate() throws Exception {
BundleImpl identicalBundle = mockBundleImpl(1L, "foo", "1.2.1.a");
BundleImpl differentBundle = mockBundleImpl(2L, "foo", "1.2.1");
CollisionHook testCollisionHook = new CollisionHook() {
@Override
public void filterCollisions(int operationType, Bundle target, Collection<Bundle> collisionCandidates) {
if ((target.getBundleId() == 3L) && (operationType == CollisionHook.UPDATING)) {
collisionCandidates.clear();
}
}
};
@SuppressWarnings("unchecked") ServiceReference<CollisionHook> chRef = Mockito.mock(ServiceReference.class);
Map<String, Object> config = new HashMap<String, Object>();
config.put(Constants.FRAMEWORK_BSNVERSION, Constants.FRAMEWORK_BSNVERSION_MANAGED);
// Mock the framework
StatefulResolver mockResolver = Mockito.mock(StatefulResolver.class);
Felix felixMock = Mockito.mock(Felix.class);
Mockito.when(felixMock.getConfig()).thenReturn(config);
HookRegistry hReg = mock(HookRegistry.class);
when(hReg.getHooks(CollisionHook.class)).thenReturn(Collections.singleton(chRef));
when(felixMock.getHookRegistry()).thenReturn(hReg);
Mockito.when(felixMock.getResolver()).thenReturn(mockResolver);
Mockito.when(felixMock.getBundles()).thenReturn(new Bundle[] { differentBundle, identicalBundle });
Mockito.when(felixMock.getService(felixMock, chRef, false)).thenReturn(testCollisionHook);
// Mock the archive of the bundle being installed
Map<String, Object> headerMap = new HashMap<String, Object>();
headerMap.put(Constants.BUNDLE_SYMBOLICNAME, "zar");
headerMap.put(Constants.BUNDLE_VERSION, "1.2.1.a");
headerMap.put(Constants.BUNDLE_MANIFESTVERSION, "2");
BundleArchiveRevision archiveRevision = Mockito.mock(BundleArchiveRevision.class);
Mockito.when(archiveRevision.getManifestHeader()).thenReturn(headerMap);
BundleArchive archive = Mockito.mock(BundleArchive.class);
Mockito.when(archive.getCurrentRevision()).thenReturn(archiveRevision);
Mockito.when(archive.getId()).thenReturn(3L);
BundleImpl bi = new BundleImpl(felixMock, null, archive);
assertEquals("zar", bi.getSymbolicName());
// Do the revise operation, change the bsn to foo
headerMap.put(Constants.BUNDLE_SYMBOLICNAME, "foo");
bi.revise(null, null);
assertEquals("foo", bi.getSymbolicName());
}
Aggregations