1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
/*******************************************************************************
* Copyright (c) 2003, 2010 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
*******************************************************************************/
package org.eclipse.osgi.internal.loader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.osgi.framework.adaptor.BundleData;
import org.eclipse.osgi.framework.internal.core.*;
import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.framework.util.KeyedHashSet;
import org.eclipse.osgi.framework.util.SecureAction;
import org.eclipse.osgi.internal.composite.CompositeBase;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.ExportPackageDescription;
import org.osgi.framework.*;
import org.osgi.service.packageadmin.RequiredBundle;
/*
* The BundleLoaderProxy proxies a BundleLoader object for a Bundle. This
* allows for a Bundle's depedencies to be linked without forcing the
* creating of the BundleLoader or BundleClassLoader objects. This class
* keeps track of the depedencies between the bundles installed in the
* Framework.
*/
public class BundleLoaderProxy implements RequiredBundle, BundleReference {
static SecureAction secureAction = AccessController.doPrivileged(SecureAction.createSecureAction());
// The BundleLoader that this BundleLoaderProxy is managing
private BundleLoader loader;
// The Bundle that this BundleLoaderProxy is for
final private BundleHost bundle;
// the BundleDescription for the Bundle
final private BundleDescription description;
// the BundleData for the bundle revision
final private BundleData data;
// Indicates if this BundleLoaderProxy is stale;
// this is true when the bundle is updated or uninstalled.
private boolean stale = false;
// cached of package sources for the bundle
final private KeyedHashSet pkgSources;
public BundleLoaderProxy(BundleHost bundle, BundleDescription description) {
this.bundle = bundle;
this.description = description;
this.pkgSources = new KeyedHashSet(false);
this.data = bundle.getBundleData();
}
public BundleLoader getBundleLoader() {
if (System.getSecurityManager() == null)
return getBundleLoader0();
return AccessController.doPrivileged(new PrivilegedAction<BundleLoader>() {
public BundleLoader run() {
return getBundleLoader0();
}
});
}
synchronized BundleLoader getBundleLoader0() {
if (loader != null)
return loader;
if (bundle.isResolved()) {
try {
if (bundle.getBundleId() == 0) // this is the system bundle
loader = new SystemBundleLoader(bundle, this);
else
loader = new BundleLoader(bundle, this);
} catch (BundleException e) {
bundle.getFramework().publishFrameworkEvent(FrameworkEvent.ERROR, bundle, e);
return null;
}
}
return loader;
}
public BundleLoader getBasicBundleLoader() {
return loader;
}
public AbstractBundle getBundleHost() {
return bundle;
}
void setStale() {
stale = true;
}
public boolean isStale() {
return stale;
}
public String toString() {
String symbolicName = bundle.getSymbolicName();
StringBuffer sb = new StringBuffer(symbolicName == null ? bundle.getBundleData().getLocation() : symbolicName);
sb.append("; ").append(Constants.BUNDLE_VERSION_ATTRIBUTE); //$NON-NLS-1$
sb.append("=\"").append(description.getVersion().toString()).append("\""); //$NON-NLS-1$//$NON-NLS-2$
return sb.toString();
}
public org.osgi.framework.Bundle getBundle() {
if (isStale())
return null;
return bundle;
}
public BundleData getBundleData() {
return data;
}
public Bundle[] getRequiringBundles() {
if (isStale())
return null;
// This is VERY slow; but never gets called in regular execution.
BundleDescription[] dependents = description.getDependents();
if (dependents == null || dependents.length == 0)
return new Bundle[0];
List<Bundle> result = new ArrayList<Bundle>(dependents.length);
for (int i = 0; i < dependents.length; i++)
addRequirers(dependents[i], result);
return result.toArray(new org.osgi.framework.Bundle[result.size()]);
}
void addRequirers(BundleDescription dependent, List<Bundle> result) {
if (dependent.getHost() != null) // don't look in fragments.
return;
BundleLoaderProxy dependentProxy = getBundleLoader().getLoaderProxy(dependent);
if (dependentProxy == null)
return; // bundle must have been uninstalled
if (result.contains(dependentProxy.bundle))
return; // prevent endless recusion
BundleLoader dependentLoader = dependentProxy.getBundleLoader();
BundleLoaderProxy[] requiredBundles = dependentLoader.requiredBundles;
int[] reexportTable = dependentLoader.reexportTable;
if (requiredBundles == null)
return;
int size = reexportTable == null ? 0 : reexportTable.length;
int reexportIndex = 0;
for (int i = 0; i < requiredBundles.length; i++) {
if (requiredBundles[i] == this) {
result.add(dependentProxy.bundle);
if (reexportIndex < size && reexportTable[reexportIndex] == i) {
reexportIndex++;
BundleDescription[] dependents = dependent.getDependents();
if (dependents == null)
return;
for (int j = 0; j < dependents.length; j++)
dependentProxy.addRequirers(dependents[j], result);
}
return;
}
}
return;
}
public String getSymbolicName() {
return description.getSymbolicName();
}
public Version getVersion() {
return description.getVersion();
}
public boolean isRemovalPending() {
return description.isRemovalPending();
}
public BundleDescription getBundleDescription() {
return description;
}
PackageSource getPackageSource(String pkgName) {
// getByKey is called outside of a synch block because we really do not
// care too much of duplicates getting created. Only the first one will
// successfully get stored into pkgSources
PackageSource pkgSource = (PackageSource) pkgSources.getByKey(pkgName);
if (pkgSource == null) {
pkgSource = new SingleSourcePackage(pkgName, this);
synchronized (pkgSources) {
pkgSources.add(pkgSource);
}
}
return pkgSource;
}
public boolean inUse() {
return (description.getDependents().length > 0) || ((bundle instanceof CompositeBase) && description.getResolvedImports().length > 0);
}
boolean forceSourceCreation(ExportPackageDescription export) {
boolean strict = Constants.STRICT_MODE.equals(secureAction.getProperty(Constants.OSGI_RESOLVER_MODE));
return (export.getDirective(Constants.INCLUDE_DIRECTIVE) != null) || (export.getDirective(Constants.EXCLUDE_DIRECTIVE) != null) || (strict && export.getDirective(Constants.FRIENDS_DIRECTIVE) != null);
}
// creates a PackageSource from an ExportPackageDescription. This is called when initializing
// a BundleLoader to ensure that the proper PackageSource gets created and used for
// filtered and reexport packages. The storeSource flag is used by initialize to indicate
// that the source for special case package sources (filtered or re-exported should be stored
// in the cache. if this flag is set then a normal SinglePackageSource will not be created
// (i.e. it will be created lazily)
public PackageSource createPackageSource(ExportPackageDescription export, boolean storeSource) {
PackageSource pkgSource = null;
// check to see if it is a filtered export
String includes = (String) export.getDirective(Constants.INCLUDE_DIRECTIVE);
String excludes = (String) export.getDirective(Constants.EXCLUDE_DIRECTIVE);
String[] friends = (String[]) export.getDirective(Constants.FRIENDS_DIRECTIVE);
if (friends != null) {
boolean strict = Constants.STRICT_MODE.equals(secureAction.getProperty(Constants.OSGI_RESOLVER_MODE));
if (!strict)
friends = null; // do not pay attention to friends if not in strict mode
}
if (includes != null || excludes != null || friends != null) {
pkgSource = new FilteredSourcePackage(export.getName(), this, includes, excludes, friends);
}
if (storeSource) {
// if the package source is not null then store the source only if it is not already present;
// getByKey is called outside of a synch block because we really do not
// care too much of duplicates getting created. Only the first one will
// successfully get stored into pkgSources
if (pkgSource != null && pkgSources.getByKey(export.getName()) == null)
synchronized (pkgSources) {
pkgSources.add(pkgSource);
}
} else {
// we are not storing the special case sources, but pkgSource == null this means this
// is a normal package source; get it and return it.
if (pkgSource == null) {
pkgSource = getPackageSource(export.getName());
// the first export cached may not be a simple single source like we need.
if (pkgSource.getClass() != SingleSourcePackage.class)
return new SingleSourcePackage(export.getName(), this);
}
}
return pkgSource;
}
}
|