Author: gnodet Date: Fri Jan 7 15:50:49 2011 New Revision: 1056363 URL: http://svn.apache.org/viewvc?rev=1056363&view=rev Log: [KARAF-358] When the feature service calls refresh(), it should wait for the refresh to happen before returning
Modified: karaf/branches/karaf-2.1.x/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java karaf/branches/karaf-2.1.x/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesServiceImplTest.java Modified: karaf/branches/karaf-2.1.x/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.1.x/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java?rev=1056363&r1=1056362&r2=1056363&view=diff ============================================================================== --- karaf/branches/karaf-2.1.x/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java (original) +++ karaf/branches/karaf-2.1.x/features/core/src/main/java/org/apache/karaf/features/internal/FeaturesServiceImpl.java Fri Jan 7 15:50:49 2011 @@ -74,7 +74,7 @@ import static java.lang.String.format; * installing the needed bundles. * */ -public class FeaturesServiceImpl implements FeaturesService { +public class FeaturesServiceImpl implements FeaturesService, FrameworkListener { public static final String CONFIG_KEY = "org.apache.karaf.features.configKey"; @@ -94,6 +94,8 @@ public class FeaturesServiceImpl impleme private List<FeaturesListener> listeners = new CopyOnWriteArrayList<FeaturesListener>(); private ThreadLocal<Repository> repo = new ThreadLocal<Repository>(); private EventAdminListener eventAdminListener; + private final Object refreshLock = new Object(); + private long refreshTimeout = 5000; public FeaturesServiceImpl() { } @@ -138,6 +140,14 @@ public class FeaturesServiceImpl impleme this.resolverTimeout = resolverTimeout; } + public long getRefreshTimeout() { + return refreshTimeout; + } + + public void setRefreshTimeout(long refreshTimeout) { + this.refreshTimeout = refreshTimeout; + } + public void registerListener(FeaturesListener listener) { listeners.add(listener); for (Repository repository : listRepositories()) { @@ -291,7 +301,7 @@ public class FeaturesServiceImpl impleme } if (refresh) { LOGGER.info("Refreshing bundles: {}", sb.toString()); - getPackageAdmin().refreshPackages(bundlesToRefresh.toArray(new Bundle[bundlesToRefresh.size()])); + refreshPackages(bundlesToRefresh.toArray(new Bundle[bundlesToRefresh.size()])); } } } @@ -644,9 +654,7 @@ public class FeaturesServiceImpl impleme b.uninstall(); } } - if (getPackageAdmin() != null) { - getPackageAdmin().refreshPackages(null); - } + refreshPackages(null); callListeners(new FeatureEvent(feature, FeatureEvent.EventType.FeatureInstalled, false)); saveState(); } @@ -735,6 +743,9 @@ public class FeaturesServiceImpl impleme } public void start() throws Exception { + // Register FrameworkEventListener + bundleContext.addFrameworkListener(this); + // Register EventAdmin listener EventAdminListener listener = null; try { getClass().getClassLoader().loadClass("org.osgi.service.event.EventAdmin"); @@ -744,6 +755,7 @@ public class FeaturesServiceImpl impleme LOGGER.debug("EventAdmin package is not available, just don't use it"); } this.eventAdminListener = listener; + // Load State if (!loadState()) { if (uris != null) { for (URI uri : uris) { @@ -756,6 +768,7 @@ public class FeaturesServiceImpl impleme } saveState(); } + // Install boot features if (boot != null && !bootFeaturesInstalled) { new Thread() { public void run() { @@ -788,12 +801,30 @@ public class FeaturesServiceImpl impleme } public void stop() throws Exception { + bundleContext.removeFrameworkListener(this); uris = new HashSet<URI>(repositories.keySet()); while (!repositories.isEmpty()) { internalRemoveRepository(repositories.keySet().iterator().next()); } } + public void frameworkEvent(FrameworkEvent event) { + if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) { + synchronized (refreshLock) { + refreshLock.notifyAll(); + } + } + } + + protected void refreshPackages(Bundle[] bundles) throws InterruptedException { + if (getPackageAdmin() != null) { + synchronized (refreshLock) { + getPackageAdmin().refreshPackages(bundles); + refreshLock.wait(refreshTimeout); + } + } + } + protected String[] parsePid(String pid) { int n = pid.indexOf('-'); if (n > 0) { Modified: karaf/branches/karaf-2.1.x/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesServiceImplTest.java URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.1.x/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesServiceImplTest.java?rev=1056363&r1=1056362&r2=1056363&view=diff ============================================================================== --- karaf/branches/karaf-2.1.x/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesServiceImplTest.java (original) +++ karaf/branches/karaf-2.1.x/features/core/src/test/java/org/apache/karaf/features/internal/FeaturesServiceImplTest.java Fri Jan 7 15:50:49 2011 @@ -27,6 +27,7 @@ import org.apache.karaf.features.Feature import org.apache.felix.utils.manifest.Clause; import org.easymock.EasyMock; import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkListener; import static org.easymock.EasyMock.*; @@ -102,6 +103,8 @@ public class FeaturesServiceImplTest ext public void testStartDoesNotFailWithOneInvalidUri() { BundleContext bundleContext = EasyMock.createMock(BundleContext.class); expect(bundleContext.getDataFile(EasyMock.<String>anyObject())).andReturn(dataFile).anyTimes(); + bundleContext.addFrameworkListener(EasyMock.<FrameworkListener>anyObject()); + bundleContext.removeFrameworkListener(EasyMock.<FrameworkListener>anyObject()); replay(bundleContext); FeaturesServiceImpl service = new FeaturesServiceImpl(); service.setBundleContext(bundleContext);