blob: 22819def4de424f3d501f168d6028a770f1c4af2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Rob Harrop - SpringSource Inc. (bug 247521)
*******************************************************************************/
package org.eclipse.osgi.framework.internal.core;
import java.util.*;
import org.eclipse.osgi.framework.util.KeyedHashSet;
import org.osgi.framework.Version;
/**
* The BundleRepository holds all installed Bundle object for the
* Framework. The BundleRepository is also used to mark and unmark
* bundle dependancies.
*
* <p>
* This class is internally synchronized and supports client locking. Clients
* wishing to perform threadsafe composite operations on instances of this
* class can synchronize on the instance itself when doing these operations.
*/
public final class BundleRepository {
/** bundles by install order */
private ArrayList bundlesByInstallOrder;
/** bundles keyed by bundle Id */
private KeyedHashSet bundlesById;
/** bundles keyed by SymbolicName */
private HashMap bundlesBySymbolicName;
public BundleRepository(int initialCapacity) {
synchronized (this) {
bundlesByInstallOrder = new ArrayList(initialCapacity);
bundlesById = new KeyedHashSet(initialCapacity, true);
bundlesBySymbolicName = new HashMap(initialCapacity);
}
}
/**
* Gets a list of bundles ordered by install order.
* @return List of bundles by install order.
*/
public synchronized List getBundles() {
return bundlesByInstallOrder;
}
/**
* Gets a bundle by its bundle Id.
* @param bundleId
* @return a bundle with the specified id or null if one does not exist
*/
public synchronized AbstractBundle getBundle(long bundleId) {
Long key = new Long(bundleId);
return (AbstractBundle) bundlesById.getByKey(key);
}
public synchronized AbstractBundle[] getBundles(String symbolicName) {
if (Constants.SYSTEM_BUNDLE_SYMBOLICNAME.equals(symbolicName))
symbolicName = Constants.getInternalSymbolicName();
return (AbstractBundle[]) bundlesBySymbolicName.get(symbolicName);
}
public synchronized AbstractBundle getBundle(String symbolicName, Version version) {
AbstractBundle[] bundles = getBundles(symbolicName);
if (bundles != null) {
if (bundles.length > 0) {
for (int i = 0; i < bundles.length; i++) {
if (bundles[i].getVersion().equals(version)) {
return bundles[i];
}
}
}
}
return null;
}
public synchronized void add(AbstractBundle bundle) {
bundlesByInstallOrder.add(bundle);
bundlesById.add(bundle);
addSymbolicName(bundle);
}
private void addSymbolicName(AbstractBundle bundle) {
String symbolicName = bundle.getSymbolicName();
if (symbolicName == null)
return;
AbstractBundle[] bundles = (AbstractBundle[]) bundlesBySymbolicName.get(symbolicName);
if (bundles == null) {
// making the initial capacity on this 1 since it
// should be rare that multiple version exist
bundles = new AbstractBundle[1];
bundles[0] = bundle;
bundlesBySymbolicName.put(symbolicName, bundles);
return;
}
ArrayList list = new ArrayList(bundles.length + 1);
// find place to insert the bundle
Version newVersion = bundle.getVersion();
boolean added = false;
for (int i = 0; i < bundles.length; i++) {
AbstractBundle oldBundle = bundles[i];
Version oldVersion = oldBundle.getVersion();
if (!added && newVersion.compareTo(oldVersion) >= 0) {
added = true;
list.add(bundle);
}
list.add(oldBundle);
}
if (!added) {
list.add(bundle);
}
bundles = new AbstractBundle[list.size()];
list.toArray(bundles);
bundlesBySymbolicName.put(symbolicName, bundles);
}
public synchronized boolean remove(AbstractBundle bundle) {
// remove by bundle ID
boolean found = bundlesById.remove(bundle);
if (!found)
return false;
// remove by install order
bundlesByInstallOrder.remove(bundle);
// remove by symbolic name
String symbolicName = bundle.getSymbolicName();
if (symbolicName == null)
return true;
removeSymbolicName(symbolicName, bundle);
return true;
}
private void removeSymbolicName(String symbolicName, AbstractBundle bundle) {
AbstractBundle[] bundles = (AbstractBundle[]) bundlesBySymbolicName.get(symbolicName);
if (bundles == null)
return;
// found some bundles with the global name.
// remove all references to the specified bundle.
int numRemoved = 0;
for (int i = 0; i < bundles.length; i++) {
if (bundle == bundles[i]) {
numRemoved++;
bundles[i] = null;
}
}
if (numRemoved > 0) {
if (bundles.length - numRemoved <= 0) {
// no bundles left in the array remove the array from the hash
bundlesBySymbolicName.remove(symbolicName);
} else {
// create a new array with the null entries removed.
AbstractBundle[] newBundles = new AbstractBundle[bundles.length - numRemoved];
int indexCnt = 0;
for (int i = 0; i < bundles.length; i++) {
if (bundles[i] != null) {
newBundles[indexCnt] = bundles[i];
indexCnt++;
}
}
bundlesBySymbolicName.put(symbolicName, newBundles);
}
}
}
public synchronized void update(String oldSymbolicName, AbstractBundle bundle) {
if (oldSymbolicName != null) {
if (!oldSymbolicName.equals(bundle.getSymbolicName())) {
removeSymbolicName(oldSymbolicName, bundle);
addSymbolicName(bundle);
}
} else {
addSymbolicName(bundle);
}
}
public synchronized void removeAllBundles() {
bundlesByInstallOrder.clear();
bundlesById = new KeyedHashSet();
bundlesBySymbolicName.clear();
}
}