Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 179476 Details for
Bug 326011
Changes to resolver hook to use a resolver hook factory
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
patch
326011.txt (text/plain), 73.78 KB, created by
Thomas Watson
on 2010-09-23 15:01:57 EDT
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Thomas Watson
Created:
2010-09-23 15:01:57 EDT
Size:
73.78 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.osgi >Index: .settings/.api_filters >=================================================================== >RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.osgi/.settings/.api_filters,v >retrieving revision 1.37 >diff -u -r1.37 .api_filters >--- .settings/.api_filters 8 Sep 2010 18:19:31 -0000 1.37 >+++ .settings/.api_filters 23 Sep 2010 19:00:48 -0000 >@@ -791,6 +791,13 @@ > </message_arguments> > </filter> > </resource> >+<resource path="osgi/src/org/osgi/framework/hooks/resolver/ResolverHookFactory.java" type="org.osgi.framework.hooks.resolver.ResolverHookFactory"> >+<filter comment="Ignore OSGi API" id="1110441988"> >+<message_arguments> >+<message_argument value="org.osgi.framework.hooks.resolver.ResolverHookFactory"/> >+</message_arguments> >+</filter> >+</resource> > <resource path="osgi/src/org/osgi/framework/launch/Framework.java" type="org.osgi.framework.launch.Framework"> > <filter id="403984517"> > <message_arguments> >Index: core/adaptor/org/eclipse/osgi/service/resolver/State.java >=================================================================== >RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/service/resolver/State.java,v >retrieving revision 1.33 >diff -u -r1.33 State.java >--- core/adaptor/org/eclipse/osgi/service/resolver/State.java 20 Sep 2010 14:51:21 -0000 1.33 >+++ core/adaptor/org/eclipse/osgi/service/resolver/State.java 23 Sep 2010 19:00:48 -0000 >@@ -10,6 +10,7 @@ > *******************************************************************************/ > package org.eclipse.osgi.service.resolver; > >+import java.util.Collection; > import java.util.Dictionary; > import org.osgi.framework.BundleException; > import org.osgi.framework.Version; >@@ -346,7 +347,7 @@ > > /** > * Resolves the constraints contained in this state using the resolver >- * currently associated with the state in a incremental, "least-perturbing" >+ * currently associated with the state in an incremental, "least-perturbing" > * mode, and returns a delta describing the changes in resolved states and > * dependencies in the state. > * >@@ -359,14 +360,35 @@ > public StateDelta resolve(BundleDescription[] discard); > > /** >+ * Resolves the constraints contained in this state using the resolver >+ * currently associated with the state in an incremental, "least-perturbing" >+ * mode, and returns a delta describing the changes in resolved states and >+ * dependencies in the state. If discard is set to true the >+ * the descriptions contained in the resolve array will have their >+ * current resolution state discarded and will be re-resolved. >+ * This method will attempt to resolve the supplied descriptions >+ * and may attempt to resolve any other unresolved descriptions contained >+ * in this state. >+ * >+ * @param resolve an array containing descriptions for bundles to resolve. >+ * @param discard a value of true indicates the resolve descriptions >+ * should have their current resolution state discarded and re-resolved. >+ * @return a delta describing the changes in the resolved state and >+ * interconnections. >+ * @since 3.7 >+ */ >+ public StateDelta resolve(BundleDescription[] resolve, boolean discard); >+ >+ /** > * Sets the version overrides which are to be applied during the resolutoin > * of this state. Version overrides allow external forces to > * refine/override the version constraints setup by the components in the > * state. > * > * @param value >+ * @deprecated The exact form of this has never been defined. There is >+ * no alternative method available. > */ >- // TODO the exact form of this is not defined as yet. > public void setOverrides(Object value); > > /** >@@ -385,6 +407,26 @@ > public BundleDescription[] getRemovalPending(); > > /** >+ * Returns the dependency closure for the specified bundles. >+ * >+ * <p> >+ * A graph of bundles is computed starting with the specified bundles. The >+ * graph is expanded by adding any bundle that is either wired to a package >+ * that is currently exported by a bundle in the graph or requires a bundle >+ * in the graph. The graph is fully constructed when there is no bundle >+ * outside the graph that is wired to a bundle in the graph. The graph may >+ * contain removal pending bundles. >+ * >+ * @param bundles The initial bundles for which to generate the dependency >+ * closure. >+ * @return A collection containing a snapshot of the dependency closure of >+ * the specified bundles, or an empty collection if there were no >+ * specified bundles. >+ * @since 3.7 >+ */ >+ public Collection<BundleDescription> getDependencyClosure(Collection<BundleDescription> bundles); >+ >+ /** > * Returns whether this state is empty. > * @return <code>true</code> if this state is empty, <code>false</code> > * otherwise >Index: core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHook.java >=================================================================== >RCS file: core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHook.java >diff -N core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHook.java >--- core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHook.java 8 Sep 2010 17:56:31 -0000 1.3 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,178 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 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.framework.internal.core; >- >-import java.util.*; >-import org.eclipse.osgi.framework.debug.Debug; >-import org.eclipse.osgi.internal.serviceregistry.*; >-import org.eclipse.osgi.util.NLS; >-import org.osgi.framework.*; >-import org.osgi.framework.hooks.resolver.ResolverHook; >-import org.osgi.framework.wiring.BundleRevision; >-import org.osgi.framework.wiring.Capability; >- >-/** >- * This class encapsulates the delegation to ResolverHooks that are registered with the service >- * registry. This way the resolver implementation only has to call out to a single hook >- * which does all the necessary service registry lookups. >- * >- * This class is not thread safe and expects external synchronization. >- * >- */ >-public class CoreResolverHook implements ResolverHook { >- // need a tuple to hold the service reference and hook object >- // do not use a map for performance reasons; no need to hash based on a key. >- static class HookReference { >- public HookReference(ServiceReferenceImpl<ResolverHook> reference, ResolverHook hook) { >- this.reference = reference; >- this.hook = hook; >- } >- >- final ServiceReferenceImpl<ResolverHook> reference; >- final ResolverHook hook; >- } >- >- private final BundleContextImpl context; >- private final ServiceRegistry registry; >- private final List<HookReference> hooks = new ArrayList<HookReference>(0); >- >- public CoreResolverHook(BundleContextImpl context, ServiceRegistry registry) { >- this.context = context; >- this.registry = registry; >- } >- >- private void handleHookException(Throwable t, ResolverHook hook, String method, Bundle hookBundle) { >- if (Debug.DEBUG_HOOKS) { >- Debug.println(hook.getClass().getName() + "." + method + "() exception: " + t.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ >- Debug.printStackTrace(t); >- } >- // allow the adaptor to handle this unexpected error >- context.framework.getAdaptor().handleRuntimeError(t); >- ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_EXCEPTION, hook.getClass().getName(), method), t); >- context.framework.publishFrameworkEvent(FrameworkEvent.ERROR, hookBundle, se); >- } >- >- private ServiceReferenceImpl<ResolverHook>[] getHookReferences() { >- try { >- @SuppressWarnings("unchecked") >- ServiceReferenceImpl<ResolverHook>[] result = (ServiceReferenceImpl<ResolverHook>[]) registry.getServiceReferences(context, ResolverHook.class.getName(), null, false, false); >- return result; >- } catch (InvalidSyntaxException e) { >- // cannot happen; no filter >- return null; >- } >- } >- >- public void begin() { >- if (Debug.DEBUG_HOOKS) { >- Debug.println("ResolverHook.begin"); //$NON-NLS-1$ >- } >- ServiceReferenceImpl<ResolverHook>[] refs = getHookReferences(); >- if (refs == null || refs.length == 0) >- return; >- for (ServiceReferenceImpl<ResolverHook> hookRef : refs) { >- ResolverHook hook = context.getService(hookRef); >- if (hook != null) { >- hooks.add(new HookReference(hookRef, hook)); >- try { >- hook.begin(); >- } catch (Throwable t) { >- handleHookException(t, hook, "begin", hookRef.getBundle()); //$NON-NLS-1$ >- } >- } >- } >- } >- >- public void filterResolvable(Collection<BundleRevision> candidates) { >- if (Debug.DEBUG_HOOKS) { >- Debug.println("ResolverHook.filterResolvable(" + candidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ >- } >- if (hooks.isEmpty()) >- return; >- candidates = new ShrinkableCollection<BundleRevision>(candidates); >- for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) { >- HookReference hookRef = iHooks.next(); >- if (hookRef.reference.getBundle() == null) { >- iHooks.remove(); >- } else { >- try { >- hookRef.hook.filterResolvable(candidates); >- } catch (Throwable t) { >- handleHookException(t, hookRef.hook, "filterResolvable", hookRef.reference.getBundle()); //$NON-NLS-1$ >- } >- } >- } >- } >- >- public void filterSingletonCollisions(Capability singleton, Collection<Capability> collisionCandidates) { >- if (Debug.DEBUG_HOOKS) { >- Debug.println("ResolverHook.filterSingletonCollisions(" + singleton + ", " + collisionCandidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ >- } >- if (hooks.isEmpty()) >- return; >- collisionCandidates = new ShrinkableCollection<Capability>(collisionCandidates); >- for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) { >- HookReference hookRef = iHooks.next(); >- if (hookRef.reference.getBundle() == null) { >- iHooks.remove(); >- } else { >- try { >- hookRef.hook.filterSingletonCollisions(singleton, collisionCandidates); >- } catch (Throwable t) { >- handleHookException(t, hookRef.hook, "filterSingletonCollisions", hookRef.reference.getBundle()); //$NON-NLS-1$ >- } >- } >- } >- } >- >- public void filterMatches(BundleRevision requirer, Collection<Capability> candidates) { >- if (Debug.DEBUG_HOOKS) { >- Debug.println("ResolverHook.filterMatches(" + requirer + ", " + candidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ >- } >- if (hooks.isEmpty()) >- return; >- candidates = new ShrinkableCollection<Capability>(candidates); >- for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) { >- HookReference hookRef = iHooks.next(); >- if (hookRef.reference.getBundle() == null) { >- iHooks.remove(); >- } else { >- try { >- hookRef.hook.filterMatches(requirer, candidates); >- } catch (Throwable t) { >- handleHookException(t, hookRef.hook, "filterMatches", hookRef.reference.getBundle()); //$NON-NLS-1$ >- } >- } >- } >- } >- >- public void end() { >- if (Debug.DEBUG_HOOKS) { >- Debug.println("ResolverHook.end"); //$NON-NLS-1$ >- } >- if (hooks.isEmpty()) >- return; >- for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) { >- HookReference hookRef = iHooks.next(); >- // We do not remove unregistered services here because we are going to remove of of them at the end >- if (hookRef.reference.getBundle() != null) { >- try { >- hookRef.hook.end(); >- } catch (Throwable t) { >- handleHookException(t, hookRef.hook, "end", hookRef.reference.getBundle()); //$NON-NLS-1$ >- } >- context.ungetService(hookRef.reference); >- } >- } >- hooks.clear(); >- } >- >-} >Index: core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHookFactory.java >=================================================================== >RCS file: core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHookFactory.java >diff -N core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHookFactory.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ core/framework/org/eclipse/osgi/framework/internal/core/CoreResolverHookFactory.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,188 @@ >+/******************************************************************************* >+ * Copyright (c) 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.framework.internal.core; >+ >+import java.util.*; >+import org.eclipse.osgi.framework.debug.Debug; >+import org.eclipse.osgi.internal.serviceregistry.*; >+import org.eclipse.osgi.util.NLS; >+import org.osgi.framework.*; >+import org.osgi.framework.hooks.resolver.ResolverHook; >+import org.osgi.framework.hooks.resolver.ResolverHookFactory; >+import org.osgi.framework.wiring.BundleRevision; >+import org.osgi.framework.wiring.Capability; >+ >+/** >+ * This class encapsulates the delegation to ResolverHooks that are registered with the service >+ * registry. This way the resolver implementation only has to call out to a single hook >+ * which does all the necessary service registry lookups. >+ * >+ * This class is not thread safe and expects external synchronization. >+ * >+ */ >+public class CoreResolverHookFactory implements ResolverHookFactory { >+ // need a tuple to hold the service reference and hook object >+ // do not use a map for performance reasons; no need to hash based on a key. >+ static class HookReference { >+ public HookReference(ServiceReferenceImpl<ResolverHookFactory> reference, ResolverHook hook) { >+ this.reference = reference; >+ this.hook = hook; >+ } >+ >+ final ServiceReferenceImpl<ResolverHookFactory> reference; >+ final ResolverHook hook; >+ } >+ >+ private final BundleContextImpl context; >+ private final ServiceRegistry registry; >+ >+ public CoreResolverHookFactory(BundleContextImpl context, ServiceRegistry registry) { >+ this.context = context; >+ this.registry = registry; >+ } >+ >+ void handleHookException(Throwable t, Object hook, String method, Bundle hookBundle) { >+ if (Debug.DEBUG_HOOKS) { >+ Debug.println(hook.getClass().getName() + "." + method + "() exception: " + t.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ >+ Debug.printStackTrace(t); >+ } >+ // allow the adaptor to handle this unexpected error >+ context.framework.getAdaptor().handleRuntimeError(t); >+ ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_EXCEPTION, hook.getClass().getName(), method), t); >+ context.framework.publishFrameworkEvent(FrameworkEvent.ERROR, hookBundle, se); >+ } >+ >+ private ServiceReferenceImpl<ResolverHookFactory>[] getHookReferences() { >+ try { >+ @SuppressWarnings("unchecked") >+ ServiceReferenceImpl<ResolverHookFactory>[] result = (ServiceReferenceImpl<ResolverHookFactory>[]) registry.getServiceReferences(context, ResolverHookFactory.class.getName(), null, false, false); >+ return result; >+ } catch (InvalidSyntaxException e) { >+ // cannot happen; no filter >+ return null; >+ } >+ } >+ >+ public ResolverHook begin(Collection<BundleRevision> triggers) { >+ if (Debug.DEBUG_HOOKS) { >+ Debug.println("ResolverHook.begin"); //$NON-NLS-1$ >+ } >+ ServiceReferenceImpl<ResolverHookFactory>[] refs = getHookReferences(); >+ @SuppressWarnings("unchecked") >+ List<HookReference> hookRefs = refs == null ? Collections.EMPTY_LIST : new ArrayList<CoreResolverHookFactory.HookReference>(refs.length); >+ if (refs != null) >+ for (ServiceReferenceImpl<ResolverHookFactory> hookRef : refs) { >+ ResolverHookFactory factory = context.getService(hookRef); >+ if (factory != null) { >+ try { >+ ResolverHook hook = factory.begin(triggers); >+ if (hook != null) >+ hookRefs.add(new HookReference(hookRef, hook)); >+ } catch (Throwable t) { >+ handleHookException(t, factory, "begin", hookRef.getBundle()); //$NON-NLS-1$ >+ } >+ } >+ } >+ return new CoreResolverHook(hookRefs); >+ } >+ >+ class CoreResolverHook implements ResolverHook { >+ private final List<HookReference> hooks; >+ >+ CoreResolverHook(List<HookReference> hooks) { >+ this.hooks = hooks; >+ } >+ >+ public void filterResolvable(Collection<BundleRevision> candidates) { >+ if (Debug.DEBUG_HOOKS) { >+ Debug.println("ResolverHook.filterResolvable(" + candidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ >+ } >+ if (hooks.isEmpty()) >+ return; >+ candidates = new ShrinkableCollection<BundleRevision>(candidates); >+ for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) { >+ HookReference hookRef = iHooks.next(); >+ if (hookRef.reference.getBundle() == null) { >+ iHooks.remove(); >+ } else { >+ try { >+ hookRef.hook.filterResolvable(candidates); >+ } catch (Throwable t) { >+ handleHookException(t, hookRef.hook, "filterResolvable", hookRef.reference.getBundle()); //$NON-NLS-1$ >+ } >+ } >+ } >+ } >+ >+ public void filterSingletonCollisions(Capability singleton, Collection<Capability> collisionCandidates) { >+ if (Debug.DEBUG_HOOKS) { >+ Debug.println("ResolverHook.filterSingletonCollisions(" + singleton + ", " + collisionCandidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ >+ } >+ if (hooks.isEmpty()) >+ return; >+ collisionCandidates = new ShrinkableCollection<Capability>(collisionCandidates); >+ for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) { >+ HookReference hookRef = iHooks.next(); >+ if (hookRef.reference.getBundle() == null) { >+ iHooks.remove(); >+ } else { >+ try { >+ hookRef.hook.filterSingletonCollisions(singleton, collisionCandidates); >+ } catch (Throwable t) { >+ handleHookException(t, hookRef.hook, "filterSingletonCollisions", hookRef.reference.getBundle()); //$NON-NLS-1$ >+ } >+ } >+ } >+ } >+ >+ public void filterMatches(BundleRevision requirer, Collection<Capability> candidates) { >+ if (Debug.DEBUG_HOOKS) { >+ Debug.println("ResolverHook.filterMatches(" + requirer + ", " + candidates + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ >+ } >+ if (hooks.isEmpty()) >+ return; >+ candidates = new ShrinkableCollection<Capability>(candidates); >+ for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) { >+ HookReference hookRef = iHooks.next(); >+ if (hookRef.reference.getBundle() == null) { >+ iHooks.remove(); >+ } else { >+ try { >+ hookRef.hook.filterMatches(requirer, candidates); >+ } catch (Throwable t) { >+ handleHookException(t, hookRef.hook, "filterMatches", hookRef.reference.getBundle()); //$NON-NLS-1$ >+ } >+ } >+ } >+ } >+ >+ public void end() { >+ if (Debug.DEBUG_HOOKS) { >+ Debug.println("ResolverHook.end"); //$NON-NLS-1$ >+ } >+ if (hooks.isEmpty()) >+ return; >+ for (Iterator<HookReference> iHooks = hooks.iterator(); iHooks.hasNext();) { >+ HookReference hookRef = iHooks.next(); >+ // We do not remove unregistered services here because we are going to remove of of them at the end >+ if (hookRef.reference.getBundle() != null) { >+ try { >+ hookRef.hook.end(); >+ } catch (Throwable t) { >+ handleHookException(t, hookRef.hook, "end", hookRef.reference.getBundle()); //$NON-NLS-1$ >+ } >+ context.ungetService(hookRef.reference); >+ } >+ } >+ hooks.clear(); >+ } >+ } >+} >Index: core/framework/org/eclipse/osgi/framework/internal/core/PackageAdminImpl.java >=================================================================== >RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PackageAdminImpl.java,v >retrieving revision 1.86 >diff -u -r1.86 PackageAdminImpl.java >--- core/framework/org/eclipse/osgi/framework/internal/core/PackageAdminImpl.java 8 Sep 2010 17:56:32 -0000 1.86 >+++ core/framework/org/eclipse/osgi/framework/internal/core/PackageAdminImpl.java 23 Sep 2010 19:00:49 -0000 >@@ -182,9 +182,9 @@ > > public boolean resolveBundles(Bundle[] bundles) { > framework.checkAdminPermission(framework.systemBundle, AdminPermission.RESOLVE); >- doResolveBundles(null, false, null); > if (bundles == null) > bundles = framework.getAllBundles(); >+ doResolveBundles(bundles, false, null); > for (int i = 0; i < bundles.length; i++) > if (!((AbstractBundle) bundles[i]).isResolved()) > return false; >@@ -193,7 +193,7 @@ > } > > // This method is protected to enable a work around to bug 245251 >- synchronized protected void doResolveBundles(AbstractBundle[] bundles, boolean refreshPackages, FrameworkListener[] listeners) { >+ synchronized protected void doResolveBundles(Bundle[] bundles, boolean refreshPackages, FrameworkListener[] listeners) { > try { > if (Profile.PROFILE && Profile.STARTUP) > Profile.logEnter("resolve bundles"); //$NON-NLS-1$ >@@ -201,12 +201,15 @@ > State systemState = framework.adaptor.getState(); > BundleDescription[] descriptions = null; > int numBundles = bundles == null ? 0 : bundles.length; >- if (!refreshPackages) >- // in this case we must make descriptions non-null so we do >- // not force the removal pendings to be processed when resolving >- // the state. >- descriptions = new BundleDescription[0]; >- else if (numBundles > 0) { >+ if (!refreshPackages) { >+ List<BundleDescription> resolving = new ArrayList<BundleDescription>(); >+ for (Bundle bundle : bundles) { >+ BundleDescription description = ((AbstractBundle) bundle).getBundleDescription(); >+ if (((bundle.getState() & Bundle.UNINSTALLED) == 0) && description != null) >+ resolving.add(description); >+ } >+ descriptions = resolving.toArray(new BundleDescription[resolving.size()]); >+ } else if (numBundles > 0) { > // populate the resolved hosts package sources first (do this outside sync block: bug 280929) > populateLoaders(framework.getAllBundles()); > synchronized (framework.bundles) { >@@ -214,7 +217,7 @@ > List<BundleDescription> results = new ArrayList<BundleDescription>(numBundles); > BundleDelta[] addDeltas = null; > for (int i = 0; i < numBundles; i++) { >- BundleDescription description = bundles[i].getBundleDescription(); >+ BundleDescription description = ((AbstractBundle) bundles[i]).getBundleDescription(); > if (description != null && description.getBundleId() != 0 && !results.contains(description)) > results.add(description); > // add in any bundles that have the same symbolic name see bug (169593) >@@ -235,7 +238,7 @@ > descriptions = (results.size() == 0 ? null : results.toArray(new BundleDescription[results.size()])); > } > } >- BundleDelta[] delta = systemState.resolve(descriptions).getChanges(); >+ BundleDelta[] delta = systemState.resolve(descriptions, refreshPackages).getChanges(); > processDelta(delta, refreshPackages, systemState); > } catch (Throwable t) { > if (Debug.DEBUG_PACKAGEADMIN) { >@@ -743,7 +746,7 @@ > // We currently have three places this is kept (PackageAdminImpl, StateImpl and ResolverImpl) > // Using the state's because it has easy access to the uninstalled Bundle objects > BundleDescription[] removals = framework.adaptor.getState().getRemovalPending(); >- Collection<Bundle> result = new HashSet<Bundle>(); >+ Set<Bundle> result = new HashSet<Bundle>(); > for (int i = 0; i < removals.length; i++) { > Object ref = removals[i].getUserObject(); > if (ref instanceof BundleReference) >@@ -753,37 +756,28 @@ > } > > public Collection<Bundle> getDependencyClosure(Collection<Bundle> bundles) { >- State state = framework.adaptor.getState(); >- BundleDescription[] removals = state.getRemovalPending(); >+ Collection<BundleDescription> descriptions = getDescriptionClosure(bundles); > Set<Bundle> result = new HashSet<Bundle>(); >- for (Bundle bundle : bundles) { >- addDependents(bundle, result, removals, state); >+ for (BundleDescription description : descriptions) { >+ Object userObject = description.getUserObject(); >+ if (userObject instanceof BundleReference) { >+ Bundle bundle = ((BundleReference) userObject).getBundle(); >+ if (bundle != null) >+ result.add(bundle); >+ } > } > return result; > } > >- private static void addDependents(Bundle bundle, Set<Bundle> result, BundleDescription[] removals, State state) { >- if (result.contains(bundle)) >- return; // avoid cycles >- result.add(bundle); >- BundleDescription description = state.getBundle(bundle.getBundleId()); >- addDependents(description, result, removals, state); >- // check if this is a removal pending >- for (BundleDescription removed : removals) { >- if (removed.getBundleId() == bundle.getBundleId()) >- addDependents(removed, result, removals, state); >+ private Collection<BundleDescription> getDescriptionClosure(Collection<Bundle> bundles) { >+ State state = framework.adaptor.getState(); >+ Collection<BundleDescription> descriptions = new ArrayList<BundleDescription>(); >+ for (Bundle bundle : bundles) { >+ BundleDescription description = state.getBundle(bundle.getBundleId()); >+ if (description != null) >+ descriptions.add(description); > } >- >+ return state.getDependencyClosure(descriptions); > } > >- private static void addDependents(BundleDescription description, Set<Bundle> result, BundleDescription[] removals, State state) { >- if (description == null) >- return; >- BundleDescription[] dependents = description.getDependents(); >- for (BundleDescription dependent : dependents) { >- Object ref = dependent.getUserObject(); >- if (ref instanceof BundleReference) >- addDependents(((BundleReference) ref).getBundle(), result, removals, state); >- } >- } > } >Index: core/framework/org/eclipse/osgi/framework/internal/core/SystemBundleActivator.java >=================================================================== >RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemBundleActivator.java,v >retrieving revision 1.24 >diff -u -r1.24 SystemBundleActivator.java >--- core/framework/org/eclipse/osgi/framework/internal/core/SystemBundleActivator.java 8 Sep 2010 17:56:31 -0000 1.24 >+++ core/framework/org/eclipse/osgi/framework/internal/core/SystemBundleActivator.java 23 Sep 2010 19:00:49 -0000 >@@ -60,7 +60,7 @@ > framework.adaptor.frameworkStart(bc); > State state = framework.adaptor.getState(); > if (state instanceof StateImpl) >- ((StateImpl) state).setResolverHook(new CoreResolverHook((BundleContextImpl) context, framework.getServiceRegistry())); >+ ((StateImpl) state).setResolverHookFactory(new CoreResolverHookFactory((BundleContextImpl) context, framework.getServiceRegistry())); > // attempt to resolve all bundles > // this is done after the adaptor.frameworkStart has been called > // this should be the first time the resolver State is accessed >Index: osgi/src/org/osgi/framework/CapabilityPermission.java >=================================================================== >RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/CapabilityPermission.java,v >retrieving revision 1.1 >diff -u -r1.1 CapabilityPermission.java >--- osgi/src/org/osgi/framework/CapabilityPermission.java 1 Sep 2010 16:42:42 -0000 1.1 >+++ osgi/src/org/osgi/framework/CapabilityPermission.java 23 Sep 2010 19:00:49 -0000 >@@ -33,7 +33,6 @@ > import java.util.Enumeration; > import java.util.HashMap; > import java.util.HashSet; >-import java.util.Hashtable; > import java.util.List; > import java.util.Map; > import java.util.Set; >@@ -48,12 +47,12 @@ > * </ul> > * > * @ThreadSafe >- * @version $Id: 11e47883a0c36de7cd69d0436287d41f8bd30f17 $ >+ * @version $Id: 4017ce21a422bbf0d4a9d0f192104eced96bec30 $ > * @since 1.6 > */ > > public final class CapabilityPermission extends BasicPermission { >- static final long serialVersionUID = -7662148639076511574L; >+ static final long serialVersionUID = -7662148639076511574L; > /** > * The action string {@code require}. > */ >@@ -63,61 +62,50 @@ > */ > public final static String PROVIDE = "provide"; > >- private final static int ACTION_REQUIRE = 0x00000001; >- private final static int ACTION_PROVIDE = 0x00000002; >- private final static int ACTION_ALL = ACTION_REQUIRE >- | ACTION_PROVIDE; >- final static int ACTION_NONE = 0; >+ private final static int ACTION_REQUIRE = 0x00000001; >+ private final static int ACTION_PROVIDE = 0x00000002; >+ private final static int ACTION_ALL = ACTION_REQUIRE >+ | ACTION_PROVIDE; >+ final static int ACTION_NONE = 0; > > /** > * The actions mask. > */ >- transient int action_mask; >+ transient int action_mask; > > /** > * The actions in canonical form. > * > * @serial > */ >- private volatile String actions = null; >+ private volatile String actions = null; > > /** >- * The service used by this ServicePermission. Must be null if not >- * constructed with a service. >+ * The attributes of the requested capability. Must be null if not >+ * constructed with attributes. > */ >- transient final ServiceReference< ? > service; >+ transient final Map<String, Object> attributes; > > /** >- * The object classes for this ServicePermission. Must be null if not >- * constructed with a service. >+ * The bundle of the requested capability. Must be null if not constructed >+ * with bundle. > */ >- transient final String[] objectClass; >+ transient final Bundle bundle; > > /** >- * If this ServicePermission was constructed with a filter, this holds a >+ * If this CapabilityPermission was constructed with a filter, this holds a > * Filter matching object used to evaluate the filter in implies. > */ >- transient Filter filter; >+ transient Filter filter; > > /** >- * This dictionary holds the properties of the permission, used to match a >- * filter in implies. This is not initialized until necessary, and then >- * cached in this object. >+ * This map holds the properties of the permission, used to match a filter >+ * in implies. This is not initialized until necessary, and then cached in >+ * this object. > */ > private transient volatile Map<String, Object> properties; > > /** >- * True if constructed with a name and the name is "*" or ends with ".*". >- */ >- private transient boolean wildcard; >- >- /** >- * If constructed with a name and the name ends with ".*", this contains the >- * name without the final "*". >- */ >- private transient String prefix; >- >- /** > * Create a new CapabilityPermission. > * > * <p> >@@ -187,49 +175,37 @@ > * @param providingBundle The bundle providing the requested capability. > * @param actions The action {@code require}. > * @throws IllegalArgumentException If the specified action is not >- * {@code require} or any parameters are {@code null}. >+ * {@code require} or attributes or providingBundle are {@code null} >+ * . > */ > public CapabilityPermission(String namespace, Map<String, ? > attributes, > Bundle providingBundle, String actions) { > super(namespace); >- this.objectClass = null; >- this.service = null; >- // setTransients(null, parseActions(actions)); >- // this.service = reference; >- // this.objectClass = (String[]) reference >- // .getProperty(Constants.OBJECTCLASS); >+ setTransients(namespace, parseActions(actions)); >+ if (attributes == null) { >+ throw new IllegalArgumentException("attributes must not be null"); >+ } >+ if (providingBundle == null) { >+ throw new IllegalArgumentException("bundle must not be null"); >+ } >+ this.attributes = new HashMap<String, Object>(attributes); >+ this.bundle = providingBundle; > if ((action_mask & ACTION_ALL) != ACTION_REQUIRE) { > throw new IllegalArgumentException("invalid action string"); > } > } > > /** >- * Create a permission name from a ServiceReference >- * >- * @param reference ServiceReference to use to create permission name. >- * @return permission name. >- */ >- private static String createName(ServiceReference< ? > reference) { >- if (reference == null) { >- throw new IllegalArgumentException("reference must not be null"); >- } >- StringBuffer sb = new StringBuffer("(service.id="); >- sb.append(reference.getProperty(Constants.SERVICE_ID)); >- sb.append(")"); >- return sb.toString(); >- } >- >- /** >- * Package private constructor used by ServicePermissionCollection. >+ * Package private constructor used by CapabilityPermissionCollection. > * > * @param name class name > * @param mask action mask > */ > CapabilityPermission(String name, int mask) { > super(name); >- setTransients(parseFilter(name), mask); >- this.service = null; >- this.objectClass = null; >+ setTransients(name, mask); >+ this.attributes = null; >+ this.bundle = null; > } > > /** >@@ -237,22 +213,12 @@ > * > * @param mask action mask > */ >- private void setTransients(Filter f, int mask) { >+ private void setTransients(String name, int mask) { > if ((mask == ACTION_NONE) || ((mask & ACTION_ALL) != mask)) { > throw new IllegalArgumentException("invalid action string"); > } > action_mask = mask; >- filter = f; >- if (f == null) { >- String name = getName(); >- int l = name.length(); >- /* if "*" or endsWith ".*" */ >- wildcard = ((name.charAt(l - 1) == '*') && ((l == 1) || (name >- .charAt(l - 2) == '.'))); >- if (wildcard && (l > 1)) { >- prefix = name.substring(0, l - 1); >- } >- } >+ filter = parseFilter(name); > } > > /** >@@ -288,25 +254,26 @@ > // check for the known strings > int matchlen; > >- if (i >= 2 && (a[i - 2] == 'g' || a[i - 2] == 'G') >- && (a[i - 1] == 'e' || a[i - 1] == 'E') >- && (a[i] == 't' || a[i] == 'T')) { >- matchlen = 3; >+ if (i >= 6 && (a[i - 6] == 'r' || a[i - 6] == 'R') >+ && (a[i - 5] == 'e' || a[i - 5] == 'E') >+ && (a[i - 4] == 'q' || a[i - 4] == 'Q') >+ && (a[i - 3] == 'u' || a[i - 3] == 'U') >+ && (a[i - 2] == 'i' || a[i - 2] == 'I') >+ && (a[i - 1] == 'r' || a[i - 1] == 'R') >+ && (a[i] == 'e' || a[i] == 'E')) { >+ matchlen = 7; > mask |= ACTION_REQUIRE; >- > } > else >- if (i >= 7 && (a[i - 7] == 'r' || a[i - 7] == 'R') >- && (a[i - 6] == 'e' || a[i - 6] == 'E') >- && (a[i - 5] == 'g' || a[i - 5] == 'G') >- && (a[i - 4] == 'i' || a[i - 4] == 'I') >- && (a[i - 3] == 's' || a[i - 3] == 'S') >- && (a[i - 2] == 't' || a[i - 2] == 'T') >- && (a[i - 1] == 'e' || a[i - 1] == 'E') >- && (a[i] == 'r' || a[i] == 'R')) { >- matchlen = 8; >+ if (i >= 6 && (a[i - 6] == 'p' || a[i - 6] == 'P') >+ && (a[i - 5] == 'r' || a[i - 5] == 'R') >+ && (a[i - 4] == 'o' || a[i - 4] == 'O') >+ && (a[i - 3] == 'v' || a[i - 3] == 'V') >+ && (a[i - 2] == 'i' || a[i - 2] == 'I') >+ && (a[i - 1] == 'd' || a[i - 1] == 'D') >+ && (a[i] == 'e' || a[i] == 'E')) { >+ matchlen = 7; > mask |= ACTION_PROVIDE; >- > } > else { > // parse error >@@ -315,13 +282,13 @@ > } > > // make sure we didn't just match the tail of a word >- // like "ackbarfregister". Also, skip to the comma. >+ // like "ackbarfprovide". Also, skip to the comma. > seencomma = false; > while (i >= matchlen && !seencomma) { > switch (a[i - matchlen]) { > case ',' : > seencomma = true; >- /* FALLTHROUGH */ >+ /* FALLTHROUGH */ > case ' ' : > case '\r' : > case '\n' : >@@ -384,7 +351,7 @@ > return false; > } > CapabilityPermission requested = (CapabilityPermission) p; >- if (service != null) { >+ if (bundle != null) { > return false; > } > // if requested permission has a filter, then it is an invalid argument >@@ -398,8 +365,8 @@ > * Internal implies method. Used by the implies and the permission > * collection implies methods. > * >- * @param requested The requested ServicePermission which has already be >- * validated as a proper argument. The requested ServicePermission >+ * @param requested The requested CapabilityPermission which has already be >+ * validated as a proper argument. The requested CapabilityPermission > * must not have a filter expression. > * @param effective The effective actions with which to start. > * @return {@code true} if the specified permission is implied by this >@@ -412,40 +379,12 @@ > if ((effective & desired) != desired) { > return false; > } >- /* we have name of "*" */ >- if (wildcard && (prefix == null)) { >- return true; >- } >- /* if we have a filter */ >+ /* Get filter if any */ > Filter f = filter; >- if (f != null) { >- return f.matches(requested.getProperties()); >- } >- /* if requested permission not created with ServiceReference */ >- String[] requestedNames = requested.objectClass; >- if (requestedNames == null) { >+ if (f == null) { > return super.implies(requested); > } >- /* requested permission created with ServiceReference */ >- if (wildcard) { >- int pl = prefix.length(); >- for (int i = 0, l = requestedNames.length; i < l; i++) { >- String requestedName = requestedNames[i]; >- if ((requestedName.length() > pl) >- && requestedName.startsWith(prefix)) { >- return true; >- } >- } >- } >- else { >- String name = getName(); >- for (int i = 0, l = requestedNames.length; i < l; i++) { >- if (requestedNames[i].equals(name)) { >- return true; >- } >- } >- } >- return false; >+ return f.matches(requested.getProperties()); > } > > /** >@@ -510,12 +449,14 @@ > return false; > } > >- CapabilityPermission sp = (CapabilityPermission) obj; >+ CapabilityPermission cp = (CapabilityPermission) obj; > >- return (action_mask == sp.action_mask) >- && getName().equals(sp.getName()) >- && ((service == sp.service) || ((service != null) && (service >- .compareTo(sp.service) == 0))); >+ return (action_mask == cp.action_mask) >+ && getName().equals(cp.getName()) >+ && ((attributes == cp.attributes) || ((attributes != null) && (attributes >+ .equals(cp.attributes)))) >+ && ((bundle == cp.bundle) || ((bundle != null) && bundle >+ .equals(cp.bundle))); > } > > /** >@@ -526,8 +467,11 @@ > public int hashCode() { > int h = 31 * 17 + getName().hashCode(); > h = 31 * h + getActions().hashCode(); >- if (service != null) { >- h = 31 * h + service.hashCode(); >+ if (attributes != null) { >+ h = 31 * h + attributes.hashCode(); >+ } >+ if (bundle != null) { >+ h = 31 * h + bundle.hashCode(); > } > return h; > } >@@ -538,7 +482,7 @@ > */ > private synchronized void writeObject(java.io.ObjectOutputStream s) > throws IOException { >- if (service != null) { >+ if (bundle != null) { > throw new NotSerializableException("cannot serialize"); > } > // Write out the actions. The superclass takes care of the name >@@ -556,55 +500,53 @@ > throws IOException, ClassNotFoundException { > // Read in the action, then initialize the rest > s.defaultReadObject(); >- setTransients(parseFilter(getName()), parseActions(actions)); >+ setTransients(getName(), parseActions(actions)); > } >+ > /** >- * Called by {@code <@link ServicePermission#implies(Permission)>}. >+ * Called by {@code <@link CapabilityPermission#implies(Permission)>}. This >+ * method is only called on a requested permission which cannot have a >+ * filter set. > * >- * @return a dictionary of properties for this permission. >+ * @return a map of properties for this permission. > */ > private Map<String, Object> getProperties() { > Map<String, Object> result = properties; > if (result != null) { > return result; > } >- if (service == null) { >- result = new HashMap<String, Object>(1); >- if (filter == null) { >- result.put(Constants.OBJECTCLASS, new String[] {getName()}); >- } >- return properties = result; >- } >- final Map<String, Object> props = new HashMap<String, Object>(4); >- final Bundle bundle = service.getBundle(); >- if (bundle != null) { >- AccessController.doPrivileged(new PrivilegedAction<Object>() { >- public Object run() { >- props.put("id", new Long(bundle.getBundleId())); >- props.put("location", bundle.getLocation()); >- String name = bundle.getSymbolicName(); >- if (name != null) { >- props.put("name", name); >- } >- SignerProperty signer = new SignerProperty(bundle); >- if (signer.isBundleSigned()) { >- props.put("signer", signer); >- } >- return null; >+ final Map<String, Object> props = new HashMap<String, Object>(5); >+ props.put("capability.namespace", getName()); >+ if (bundle == null) { >+ return properties = props; >+ } >+ AccessController.doPrivileged(new PrivilegedAction<Object>() { >+ public Object run() { >+ props.put("id", new Long(bundle.getBundleId())); >+ props.put("location", bundle.getLocation()); >+ String name = bundle.getSymbolicName(); >+ if (name != null) { >+ props.put("name", name); >+ } >+ SignerProperty signer = new SignerProperty(bundle); >+ if (signer.isBundleSigned()) { >+ props.put("signer", signer); > } >- }); >- } >- return properties = new Properties(props, service); >+ return null; >+ } >+ }); >+ return properties = new Properties(props, attributes); > } >- >+ > private static class Properties extends AbstractMap<String, Object> { >- private final Map<String, Object> properties; >- private final ServiceReference< ? > service; >+ private final Map<String, Object> properties; >+ private final Map<String, Object> attributes; > private transient volatile Set<Map.Entry<String, Object>> entries; > >- Properties(Map<String, Object> properties, ServiceReference< ? > service) { >+ Properties(Map<String, Object> properties, >+ Map<String, Object> attributes) { > this.properties = properties; >- this.service = service; >+ this.attributes = attributes; > entries = null; > } > >@@ -614,13 +556,13 @@ > } > String key = (String) k; > if (key.charAt(0) == '@') { >- return service.getProperty(key.substring(1)); >+ return attributes.get(key.substring(1)); > } > Object value = properties.get(key); > if (value != null) { // fall back to service properties > return value; > } >- return service.getProperty(key); >+ return attributes.get(key); > } > > public Set<Map.Entry<String, Object>> entrySet() { >@@ -628,78 +570,31 @@ > return entries; > } > Set<Map.Entry<String, Object>> all = new HashSet<Map.Entry<String, Object>>( >- properties.entrySet()); >- add: for (String key : service.getPropertyKeys()) { >- for (String k : properties.keySet()) { >- if (key.equalsIgnoreCase(k)) { >- continue add; >- } >- } >- all.add(new Entry(key, service.getProperty(key))); >- } >+ attributes.size() + properties.size()); >+ all.addAll(attributes.entrySet()); >+ all.addAll(properties.entrySet()); > return entries = Collections.unmodifiableSet(all); > } >- >- private static class Entry implements Map.Entry<String, Object> { >- private final String k; >- private final Object v; >- >- Entry(String key, Object value) { >- this.k = key; >- this.v = value; >- } >- public String getKey() { >- return k; >- } >- public Object getValue() { >- return v; >- } >- public Object setValue(Object value) { >- throw new UnsupportedOperationException(); >- } >- public String toString() { >- return k + "=" + v; >- } >- public int hashCode() { >- return ((k == null) ? 0 : k.hashCode()) >- ^ ((v == null) ? 0 : v.hashCode()); >- } >- public boolean equals(Object obj) { >- if (obj == this) { >- return true; >- } >- if (!(obj instanceof Map.Entry)) { >- return false; >- } >- Map.Entry< ? , ? > e = (Map.Entry< ? , ? >) obj; >- final Object key = e.getKey(); >- if ((k == key) || ((k != null) && k.equals(key))) { >- final Object value = e.getValue(); >- if ((v == value) || ((v != null) && v.equals(value))) { >- return true; >- } >- } >- return false; >- } >- } > } > } > > /** >- * Stores a set of ServicePermission permissions. >+ * Stores a set of CapabilityPermission permissions. > * > * @see java.security.Permission > * @see java.security.Permissions > * @see java.security.PermissionCollection > */ > final class CapabilityPermissionCollection extends PermissionCollection { >- static final long serialVersionUID = 662615640374640621L; >+ static final long serialVersionUID = -615322242639008920L; >+ > /** > * Table of permissions. > * >+ * @serial > * @GuardedBy this > */ >- private transient Map<String, CapabilityPermission> permissions; >+ private Map<String, CapabilityPermission> permissions; > > /** > * Boolean saying if "*" is in the collection. >@@ -707,7 +602,7 @@ > * @serial > * @GuardedBy this > */ >- private boolean all_allowed; >+ private boolean all_allowed; > > /** > * Table of permissions with filter expressions. >@@ -715,7 +610,7 @@ > * @serial > * @GuardedBy this > */ >- private Map<String, CapabilityPermission> filterPermissions; >+ private Map<String, CapabilityPermission> filterPermissions; > > /** > * Creates an empty CapabilityPermissionCollection object. >@@ -730,10 +625,9 @@ > * > * @param permission The Permission object to add. > * @throws IllegalArgumentException If the specified permission is not a >- * ServicePermission object. >- * @throws SecurityException If this >- * {@code ServicePermissionCollection} object has been marked >- * read-only. >+ * CapabilityPermission object. >+ * @throws SecurityException If this {@code CapabilityPermissionCollection} >+ * object has been marked read-only. > */ > public void add(final Permission permission) { > if (!(permission instanceof CapabilityPermission)) { >@@ -745,14 +639,14 @@ > + "readonly PermissionCollection"); > } > >- final CapabilityPermission sp = (CapabilityPermission) permission; >- if (sp.service != null) { >+ final CapabilityPermission cp = (CapabilityPermission) permission; >+ if (cp.bundle != null) { > throw new IllegalArgumentException("cannot add to collection: " >- + sp); >+ + cp); > } >- >- final String name = sp.getName(); >- final Filter f = sp.filter; >+ >+ final String name = cp.getName(); >+ final Filter f = cp.filter; > synchronized (this) { > /* select the bucket for the permission */ > Map<String, CapabilityPermission> pc; >@@ -766,20 +660,19 @@ > pc = permissions; > } > final CapabilityPermission existing = pc.get(name); >- >+ > if (existing != null) { > final int oldMask = existing.action_mask; >- final int newMask = sp.action_mask; >+ final int newMask = cp.action_mask; > if (oldMask != newMask) { >- pc >- .put(name, new CapabilityPermission(name, oldMask >+ pc.put(name, new CapabilityPermission(name, oldMask > | newMask)); > } > } > else { >- pc.put(name, sp); >+ pc.put(name, cp); > } >- >+ > if (!all_allowed) { > if (name.equals("*")) { > all_allowed = true; >@@ -793,9 +686,8 @@ > * {@code permission}. > * > * @param permission The Permission object to compare. >- * @return {@code true} if {@code permission} is a proper >- * subset of a permission in the set; {@code false} >- * otherwise. >+ * @return {@code true} if {@code permission} is a proper subset of a >+ * permission in the set; {@code false} otherwise. > */ > public boolean implies(final Permission permission) { > if (!(permission instanceof CapabilityPermission)) { >@@ -807,44 +699,61 @@ > return false; > } > >+ String requestedName = requested.getName(); >+ final int desired = requested.action_mask; > int effective = CapabilityPermission.ACTION_NONE; >+ > Collection<CapabilityPermission> perms; > synchronized (this) { >- final int desired = requested.action_mask; >+ Map<String, CapabilityPermission> pc = permissions; >+ CapabilityPermission cp; > /* short circuit if the "*" Permission was added */ > if (all_allowed) { >- CapabilityPermission sp = permissions.get("*"); >- if (sp != null) { >- effective |= sp.action_mask; >+ cp = pc.get("*"); >+ if (cp != null) { >+ effective |= cp.action_mask; > if ((effective & desired) == desired) { > return true; > } > } > } >- >- String[] requestedNames = requested.objectClass; >- /* if requested permission not created with ServiceReference */ >- if (requestedNames == null) { >- effective |= effective(requested.getName(), desired, effective); >+ >+ /* >+ * strategy: Check for full match first. Then work our way up the >+ * name looking for matches on a.b.* >+ */ >+ cp = pc.get(requestedName); >+ if (cp != null) { >+ /* we have a direct hit! */ >+ effective |= cp.action_mask; > if ((effective & desired) == desired) { > return true; > } > } >- /* requested permission created with ServiceReference */ >- else { >- for (int i = 0, l = requestedNames.length; i < l; i++) { >- if ((effective(requestedNames[i], desired, effective) & desired) == desired) { >+ /* work our way up the tree... */ >+ int last; >+ int offset = requestedName.length() - 1; >+ while ((last = requestedName.lastIndexOf(".", offset)) != -1) { >+ requestedName = requestedName.substring(0, last + 1) + "*"; >+ cp = pc.get(requestedName); >+ if (cp != null) { >+ effective |= cp.action_mask; >+ if ((effective & desired) == desired) { > return true; > } > } >+ offset = last - 1; > } >- Map<String, CapabilityPermission> pc = filterPermissions; >+ /* >+ * we don't have to check for "*" as it was already checked before >+ * we were called. >+ */ >+ pc = filterPermissions; > if (pc == null) { > return false; > } > perms = pc.values(); > } >- > /* iterate one by one over filteredPermissions */ > for (CapabilityPermission perm : perms) { > if (perm.implies0(requested, effective)) { >@@ -855,54 +764,10 @@ > } > > /** >- * Consult permissions map to compute the effective permission for the >- * requested permission name. >- * >- * @param requestedName The requested service name. >- * @param desired The desired actions. >- * @param effective The effective actions. >- * @return The new effective actions. >- */ >- private int effective(String requestedName, final int desired, >- int effective) { >- final Map<String, CapabilityPermission> pc = permissions; >- CapabilityPermission sp = pc.get(requestedName); >- // strategy: >- // Check for full match first. Then work our way up the >- // name looking for matches on a.b.* >- if (sp != null) { >- // we have a direct hit! >- effective |= sp.action_mask; >- if ((effective & desired) == desired) { >- return effective; >- } >- } >- // work our way up the tree... >- int last; >- int offset = requestedName.length() - 1; >- while ((last = requestedName.lastIndexOf(".", offset)) != -1) { >- requestedName = requestedName.substring(0, last + 1) + "*"; >- sp = pc.get(requestedName); >- if (sp != null) { >- effective |= sp.action_mask; >- if ((effective & desired) == desired) { >- return effective; >- } >- } >- offset = last - 1; >- } >- /* >- * we don't have to check for "*" as it was already checked before we >- * were called. >- */ >- return effective; >- } >- >- /** >- * Returns an enumeration of all the {@code ServicePermission} >- * objects in the container. >+ * Returns an enumeration of all the {@code CapabilityPermission} objects in >+ * the container. > * >- * @return Enumeration of all the ServicePermission objects. >+ * @return Enumeration of all the CapabilityPermission objects. > */ > public synchronized Enumeration<Permission> elements() { > List<Permission> all = new ArrayList<Permission>(permissions.values()); >@@ -912,19 +777,17 @@ > } > return Collections.enumeration(all); > } >- >+ > /* serialization logic */ > private static final ObjectStreamField[] serialPersistentFields = { >- new ObjectStreamField("permissions", Hashtable.class), >+ new ObjectStreamField("permissions", HashMap.class), > new ObjectStreamField("all_allowed", Boolean.TYPE), > new ObjectStreamField("filterPermissions", HashMap.class) }; > > private synchronized void writeObject(ObjectOutputStream out) > throws IOException { >- Hashtable<String, CapabilityPermission> hashtable = new Hashtable<String, CapabilityPermission>( >- permissions); > ObjectOutputStream.PutField pfields = out.putFields(); >- pfields.put("permissions", hashtable); >+ pfields.put("permissions", permissions); > pfields.put("all_allowed", all_allowed); > pfields.put("filterPermissions", filterPermissions); > out.writeFields(); >@@ -933,9 +796,9 @@ > private synchronized void readObject(java.io.ObjectInputStream in) > throws IOException, ClassNotFoundException { > ObjectInputStream.GetField gfields = in.readFields(); >- Hashtable<String, CapabilityPermission> hashtable = (Hashtable<String, CapabilityPermission>) gfields >+ HashMap<String, CapabilityPermission> p = (HashMap<String, CapabilityPermission>) gfields > .get("permissions", null); >- permissions = new HashMap<String, CapabilityPermission>(hashtable); >+ permissions = p; > all_allowed = gfields.get("all_allowed", false); > HashMap<String, CapabilityPermission> fp = (HashMap<String, CapabilityPermission>) gfields > .get("filterPermissions", null); >Index: osgi/src/org/osgi/framework/hooks/resolver/ResolverHook.java >=================================================================== >RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.osgi/osgi/src/org/osgi/framework/hooks/resolver/ResolverHook.java,v >retrieving revision 1.2 >diff -u -r1.2 ResolverHook.java >--- osgi/src/org/osgi/framework/hooks/resolver/ResolverHook.java 20 Aug 2010 22:07:53 -0000 1.2 >+++ osgi/src/org/osgi/framework/hooks/resolver/ResolverHook.java 23 Sep 2010 19:00:49 -0000 >@@ -24,12 +24,12 @@ > import org.osgi.framework.wiring.FrameworkWiring; > > /** >- * OSGi Framework Resolver Hook Service. >+ * OSGi Framework Resolver Hook instances are obtained from the OSGi {@link ResolverHookFactory >+ * Framework Resolver Hook Factory} service. > * > * <p> >- * Services registered with this service interface will be called by the framework during a resolve >- * process. The framework must, at most, have one resolve process running at any given point >- * in time. A resolver hook may influence the outcome of a resolve process by removing entries >+ * A Resolver Hook instance is called by the framework during a resolve >+ * process. A resolver hook may influence the outcome of a resolve process by removing entries > * from shrinkable collections that are passed to the hook during a resolve process. A shrinkable > * collection is a {@code Collection} that supports all remove operations. Any other attempts to modify > * a shrinkable collection will result in an {@code UnsupportedOperationException} being thrown. >@@ -37,18 +37,19 @@ > * The following steps outline the way a framework uses the resolver hooks during a resolve > * process. > * <ol> >- * <li> Collect a snapshot of registered resolver hooks that will be called during the >- * current resolve process. Any hooks registered after the snapshot is taken must not be called >- * during the current resolve process. A resolver hook contained in the snapshot may become >+ * <li> Collect a snapshot of registered resolver hook factories that will be called during the >+ * current resolve process. Any hook factories registered after the snapshot is taken must not be called >+ * during the current resolve process. A resolver hook factory contained in the snapshot may become > * unregistered during the resolve process. The framework should handle this and stop calling >- * the unregistered hook for the remainder of the resolve process.</li> >- * <li> For each registered hook call the {@link #begin()} method to inform the hooks about a resolve >- * process beginning.</li> >+ * the resolver hook instance provided by the unregistered hook factory for the remainder of the resolve process.</li> >+ * <li> For each registered hook factory call the {@link ResolverHookFactory#begin(Collection)} method to inform the >+ * hooks about a resolve process beginning and to obtain a Resolver Hook instance that will be used for the duration >+ * of the resolve process.</li> > * <li> Determine the collection of unresolved bundle revisions that may be considered for resolution during > * the current resolution process and place each of the bundle revisions in a shrinkable collection > * <b>{@code R}</b>. > * <ol type="a"> >- * <li> For each registered hook call the {@link #filterResolvable(Collection)} method with the >+ * <li> For each resolver hook call the {@link #filterResolvable(Collection)} method with the > * shrinkable collection <b>{@code R}</b>.</li> > * </ol> > * </li> >@@ -66,7 +67,7 @@ > * <li> Remove the {@link Capability#BUNDLE_CAPABILITY osgi.bundle} capability provided by > * bundle revision <b>{@code B}</b> from shrinkable collection <b>{@code S}</b>. A singleton bundle > * cannot collide with itself.</li> >- * <li> For each registered hook call the {@link #filterSingletonCollisions(Capability, Collection)} >+ * <li> For each resovler hook call the {@link #filterSingletonCollisions(Capability, Collection)} > * with the {@link Capability#BUNDLE_CAPABILITY osgi.bundle} capability provided by bundle revision > * <b>{@code B}</b> and the shrinkable collection <b>{@code S}</b></li> > * <li> The shrinkable collection <b>{@code S}</b> now contains all singleton {@link Capability#BUNDLE_CAPABILITY >@@ -79,15 +80,17 @@ > * <ol type="a"> > * <li> For each requirement <b>{@code T}</b> specified by bundle revision <b>{@code B}</b> determine the > * collection of capabilities that satisfy (or match) the requirement and place each matching capability into >- * a shrinkable collection <b>{@code C}</b>.</li> >- * <li> For each registered hook call the {@link #filterMatches(BundleRevision, Collection)} with the >+ * a shrinkable collection <b>{@code C}</b>. A capability is considered to match a particular requirement >+ * if its attributes satisfy a specified requirement and the requirer bundle has permission to access the >+ * capability.</li> >+ * <li> For each resolver hook call the {@link #filterMatches(BundleRevision, Collection)} with the > * bundle revision <b>{@code B}</b> and the shrinkable collection <b>{@code C}</b>.</li> > * <li> The shrinkable collection <b>{@code C}</b> now contains all the capabilities that may be used to > * satisfy the requirement <b>{@code T}</b>. Any other capabilities that got removed from the > * shrinkable collection <b>{@code C}</b> must not be used to satisfy requirement <b>{@code T}</b>.</li> > * </ol> > * </li> >- * <li> For each registered hook call the {@link #end()} method to inform the hooks about a resolve >+ * <li> For each resolver hook call the {@link #end()} method to inform the hooks about a resolve > * process ending.</li> > * </ol> > * In all cases, the order in which the resolver hooks are called is the reverse compareTo ordering of >@@ -100,17 +103,11 @@ > * resolve process (e.g. by calling {@link Bundle#start()} or {@link FrameworkWiring#resolveBundles(Collection)}). > * The framework must detect this and throw an {@link IllegalStateException}. > * >+ * @see ResolverHookFactory > * @ThreadSafe >- * @version $Id: 17fa0cb4223f6e2e6738ac675099d5aa8b44ab46 $ >+ * @version $Id: e896c443a68b3ea287735c9c19f0b1c62bd4755d $ > */ > public interface ResolverHook { >- >- /** >- * This method is called once at the beginning of the resolve process >- * before any other methods are called on this hook. >- */ >- void begin(); >- > /** > * Filter resolvable candidates hook method. This method may be called > * multiple times during a single resolve process. >@@ -158,6 +155,10 @@ > * <p> > * All of the candidates will have the same name space and will > * match a requirement of the requirer. >+ * <p> >+ * If the Java Runtime Environment supports permissions then the collection of >+ * candidates will only contain candidates for which the requirer has permission to >+ * access. > * @param requirer the bundle revision which contains a requirement > * @param candidates a collection of candidates that match a requirement of the requirer > */ >@@ -166,9 +167,8 @@ > /** > * This method is called once at the end of the resolve process. > * After the end method is called the resolve process has ended. >- * No methods will be called on this hook except after the >- * {@link #begin() begin} method is called again to indicate >- * a new resolve process is beginning. >+ * The framework must not hold onto this resolver hook instance >+ * after end has been called. > */ > void end(); > } >Index: osgi/src/org/osgi/framework/hooks/resolver/ResolverHookFactory.java >=================================================================== >RCS file: osgi/src/org/osgi/framework/hooks/resolver/ResolverHookFactory.java >diff -N osgi/src/org/osgi/framework/hooks/resolver/ResolverHookFactory.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ osgi/src/org/osgi/framework/hooks/resolver/ResolverHookFactory.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,83 @@ >+/* >+ * Copyright (c) OSGi Alliance (2010). All Rights Reserved. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+package org.osgi.framework.hooks.resolver; >+ >+import java.util.Collection; >+ >+import org.osgi.framework.Bundle; >+import org.osgi.framework.wiring.BundleRevision; >+import org.osgi.framework.wiring.FrameworkWiring; >+ >+/** >+ * OSGi Framework Resolver Hook Factory Service. >+ * >+ * <p> >+ * Bundles registering this service will be called by the framework during >+ * a bundle resolver process to obtain a {@link ResolverHook resolver hook} >+ * instance which will be used for the duration of a resolve process. >+ * >+ * @ThreadSafe >+ * @see ResolverHook >+ * @version $Id: 18ea1ec1f14f47410a43e99be4da3b2583149722 $ >+ */ >+public interface ResolverHookFactory { >+ /** >+ * This method is called by the framework each time a resolve process begins >+ * to obtain a {@link ResolverHook resolver hook} instance. This resolver hook >+ * instance will be used for the duration of the resolve process. At the end of >+ * the resolve process the method {@link ResolverHook#end()} must be called by >+ * the framework and the framework must not hold any references of the resolver >+ * hook instance. >+ * <p> >+ * The triggers represent the collection of bundles which triggered >+ * the resolve process. This collection may be empty if the triggers >+ * cannot be determined by the framework. In most cases the triggers >+ * can easily be determined. Calling certain methods on >+ * {@link Bundle bundle} when a bundle is in the {@link Bundle#INSTALLED INSTALLED} >+ * state will cause the framework to begin a resolve process in order to resolve the >+ * bundle. The following methods will start a resolve process in this case: >+ * <ul> >+ * <li>{@link Bundle#start() start}</li> >+ * <li>{@link Bundle#loadClass(String) loadClass}</li> >+ * <li>{@link Bundle#findEntries(String, String, boolean) findEntries}</li> >+ * <li>{@link Bundle#getResource(String) getResource}</li> >+ * <li>{@link Bundle#getResources(String) getResources}</li> >+ * </ul> >+ * In such cases the collection will contain the single bundle which the >+ * framework is trying to resolve. Other cases will cause multiple bundles to be >+ * included in the trigger bundles collection. When {@link FrameworkWiring#resolveBundles(Collection) >+ * resolveBundles} is called the collection of triggers must include all the current bundle >+ * revisions for bundles passed to resolveBundles which have not been uninstalled. >+ * <p> >+ * When {@link FrameworkWiring#refreshBundles(Collection, org.osgi.framework.FrameworkListener...)} >+ * is called the collection of triggers is determined with the following steps: >+ * <ul> >+ * <li>If the collection of bundles passed is null then {@link FrameworkWiring#getRemovalPendingBundles()} >+ * is called to get the initial collection of bundles.</li> >+ * <li>The equivalent of calling {@link FrameworkWiring#getDependencyClosure(Collection)} is called with >+ * the initial collection of bundles to get the dependency closure collection of the bundles being refreshed.</li> >+ * <li>Remove any non-active bundles from the dependency closure collection.</li> >+ * <li>For each bundle remaining in the dependency closure collection get the current bundle revision >+ * and add it to the collection of triggers.</li> >+ * </ul> >+ * @param triggers an unmodifiable collection of bundles which triggered the resolve process. >+ * This collection may be empty if the collection of trigger bundles cannot be >+ * determined. >+ * @return a resolver hook instance to be used for the duration of the resolve process. >+ */ >+ ResolverHook begin(Collection<BundleRevision> triggers); >+} >Index: resolver/src/org/eclipse/osgi/internal/resolver/ReadOnlyState.java >=================================================================== >RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/ReadOnlyState.java,v >retrieving revision 1.28 >diff -u -r1.28 ReadOnlyState.java >--- resolver/src/org/eclipse/osgi/internal/resolver/ReadOnlyState.java 20 Sep 2010 14:51:21 -0000 1.28 >+++ resolver/src/org/eclipse/osgi/internal/resolver/ReadOnlyState.java 23 Sep 2010 19:00:50 -0000 >@@ -12,6 +12,7 @@ > *******************************************************************************/ > package org.eclipse.osgi.internal.resolver; > >+import java.util.Collection; > import java.util.Dictionary; > import org.eclipse.osgi.service.resolver.*; > import org.osgi.framework.BundleException; >@@ -100,6 +101,11 @@ > throw new UnsupportedOperationException(); > } > >+ public StateDelta resolve(BundleDescription[] resolve, boolean discard) { >+ throw new UnsupportedOperationException(); >+ } >+ >+ @SuppressWarnings("deprecation") > public void setOverrides(Object value) { > throw new UnsupportedOperationException(); > } >@@ -150,7 +156,8 @@ > throw new UnsupportedOperationException(); > } > >- public Dictionary<Object, Object>[] getPlatformProperties() { >+ @SuppressWarnings("rawtypes") >+ public Dictionary[] getPlatformProperties() { > return target.getPlatformProperties(); > } > >@@ -214,4 +221,8 @@ > throw new UnsupportedOperationException(); > } > >+ public Collection<BundleDescription> getDependencyClosure(Collection<BundleDescription> bundles) { >+ return target.getDependencyClosure(bundles); >+ } >+ > } >Index: resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java >=================================================================== >RCS file: /cvsroot/rt/org.eclipse.equinox/framework/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java,v >retrieving revision 1.90 >diff -u -r1.90 StateImpl.java >--- resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java 20 Sep 2010 14:51:21 -0000 1.90 >+++ resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java 23 Sep 2010 19:00:51 -0000 >@@ -25,6 +25,8 @@ > import org.eclipse.osgi.util.NLS; > import org.osgi.framework.*; > import org.osgi.framework.hooks.resolver.ResolverHook; >+import org.osgi.framework.hooks.resolver.ResolverHookFactory; >+import org.osgi.framework.wiring.BundleRevision; > > public abstract class StateImpl implements State { > private static final String OSGI_OS = "osgi.os"; //$NON-NLS-1$ >@@ -54,6 +56,7 @@ > private Dictionary<Object, Object>[] platformProperties = new Dictionary[] {new Hashtable<String, String>(PROPS.length)}; // Dictionary here because of Filter API > private long highestBundleId = -1; > private final Set<String> platformPropertyKeys = new HashSet<String>(PROPS.length); >+ private ResolverHookFactory hookFactory; > private ResolverHook hook; > > private static long cumulativeTime; >@@ -426,17 +429,15 @@ > bundle.removeDependencies(); > } > >- private StateDelta resolve(boolean incremental, BundleDescription[] reResolve) { >+ private StateDelta resolve(boolean incremental, BundleDescription[] reResolve, BundleDescription[] triggers) { > synchronized (this.monitor) { > if (resolver == null) > throw new IllegalStateException("no resolver set"); //$NON-NLS-1$ > if (resolving == true) > throw new IllegalStateException("An attempt to start a nested resolve process has been detected."); //$NON-NLS-1$ >- ResolverHook currentHook = getResolverHook(); >+ ResolverHook currentHook = null; > try { > resolving = true; >- if (currentHook != null) >- currentHook.begin(); > fullyLoad(); > long start = 0; > if (StateManager.DEBUG_PLATFORM_ADMIN_RESOLVER) >@@ -450,12 +451,21 @@ > reResolve = mergeBundles(reResolve, removed); > } > flush(reResolve); >- } >- if (resolved && reResolve == null) >- return new StateDeltaImpl(this); >- if (removalPendings.size() > 0) { >- BundleDescription[] removed = internalGetRemovalPending(); >- reResolve = mergeBundles(reResolve, removed); >+ } else { >+ if (resolved && reResolve == null) >+ return new StateDeltaImpl(this); >+ if (reResolve == null) >+ reResolve = internalGetRemovalPending(); >+ if (triggers == null) { >+ Set<BundleDescription> triggerSet = new HashSet<BundleDescription>(); >+ Collection<BundleDescription> closure = getDependencyClosure(Arrays.asList(reResolve)); >+ for (BundleDescription toRefresh : closure) { >+ Bundle bundle = toRefresh.getBundle(); >+ if (bundle != null && (bundle.getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED | Bundle.RESOLVED)) == 0) >+ triggerSet.add(toRefresh); >+ } >+ triggers = triggerSet.toArray(new BundleDescription[triggerSet.size()]); >+ } > } > // use the Headers class to handle ignoring case while matching keys (bug 180817) > @SuppressWarnings("unchecked") >@@ -467,6 +477,13 @@ > tmpPlatformProperties[i].put(key, platformProperties[i].get(key)); > } > } >+ >+ ResolverHookFactory currentFactory = hookFactory; >+ if (currentFactory != null) { >+ @SuppressWarnings("unchecked") >+ Collection<BundleRevision> triggerRevisions = Collections.unmodifiableCollection(triggers == null ? Collections.EMPTY_LIST : Arrays.asList((BundleRevision[]) triggers)); >+ currentHook = begin(triggerRevisions); >+ } > resolver.resolve(reResolve, tmpPlatformProperties); > resolved = removalPendings.size() == 0; > >@@ -526,25 +543,44 @@ > } > > public StateDelta resolve() { >- return resolve(true, null); >+ return resolve(true, null, null); > } > > public StateDelta resolve(boolean incremental) { >- return resolve(incremental, null); >+ return resolve(incremental, null, null); > } > > public StateDelta resolve(BundleDescription[] reResolve) { >- return resolve(true, reResolve); >+ return resolve(true, reResolve, null); > } > >+ public StateDelta resolve(BundleDescription[] resolve, boolean discard) { >+ BundleDescription[] reResolve = discard ? resolve : new BundleDescription[0]; >+ BundleDescription[] triggers = discard ? null : resolve; >+ return resolve(true, reResolve, triggers); >+ } >+ >+ @SuppressWarnings("deprecation") > public void setOverrides(Object value) { > throw new UnsupportedOperationException(); > } > >- public void setResolverHook(ResolverHook hook) { >+ public void setResolverHookFactory(ResolverHookFactory hookFactory) { >+ synchronized (this.monitor) { >+ this.hookFactory = hookFactory; >+ } >+ } >+ >+ private ResolverHook begin(Collection<BundleRevision> triggers) { >+ ResolverHookFactory current; >+ synchronized (this.monitor) { >+ current = this.hookFactory; >+ } >+ ResolverHook newHook = current.begin(triggers); > synchronized (this.monitor) { >- this.hook = hook; >+ this.hook = newHook; > } >+ return newHook; > } > > public ResolverHook getResolverHook() { >@@ -874,10 +910,6 @@ > return symbolicName != null ? symbolicName : Constants.getInternalSymbolicName(); > } > >- /** >- * Returns the latest versions BundleDescriptions which have old removal pending versions. >- * @return the BundleDescriptions that have removal pending versions. >- */ > public BundleDescription[] getRemovalPending() { > synchronized (this.monitor) { > return removalPendings.toArray(new BundleDescription[removalPendings.size()]); >@@ -891,6 +923,29 @@ > } > } > >+ public Collection<BundleDescription> getDependencyClosure(Collection<BundleDescription> bundles) { >+ BundleDescription[] removals = getRemovalPending(); >+ Set<BundleDescription> result = new HashSet<BundleDescription>(); >+ for (BundleDescription bundle : bundles) { >+ addDependents(bundle, result, removals); >+ } >+ return result; >+ } >+ >+ private static void addDependents(BundleDescription bundle, Set<BundleDescription> result, BundleDescription[] removals) { >+ if (result.contains(bundle)) >+ return; // avoid cycles >+ result.add(bundle); >+ BundleDescription[] dependents = bundle.getDependents(); >+ for (BundleDescription dependent : dependents) >+ addDependents(dependent, result, removals); >+ // check if this is a removal pending >+ for (BundleDescription removed : removals) { >+ if (removed.getBundleId() == bundle.getBundleId()) >+ addDependents(removed, result, removals); >+ } >+ } >+ > /** > * Returns the latest versions BundleDescriptions which have old removal pending versions. > * @return the BundleDescriptions that have removal pending versions. >@@ -915,11 +970,16 @@ > return null; > fullyLoad(); > synchronized (this.monitor) { >- ResolverHook currentHook = getResolverHook(); >+ ResolverHook currentHook = null; > try { > resolving = true; >- if (currentHook != null) >- currentHook.begin(); >+ ResolverHookFactory currentFactory = hookFactory; >+ if (currentFactory != null) { >+ Collection<BundleRevision> triggers = new ArrayList<BundleRevision>(1); >+ triggers.add(importingBundle); >+ triggers = Collections.unmodifiableCollection(triggers); >+ currentHook = begin(triggers); >+ } > // ask the resolver to resolve our dynamic import > ExportPackageDescriptionImpl result = (ExportPackageDescriptionImpl) resolver.resolveDynamicImport(importingBundle, requestedPackage); > if (result == null)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 326011
: 179476