FELIX-4734 : Web Console RESTful API should wait for asynchonous operations until they complete. Apply slightly modified patch from Valentin Valchev
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1654733 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java
index fb7a60b..7dff3cd 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BaseUpdateInstallHelper.java
@@ -21,12 +21,16 @@
import java.io.File;
import java.io.FileInputStream;
+import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.apache.felix.webconsole.SimpleWebConsolePlugin;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
import org.osgi.service.log.LogService;
import org.osgi.service.packageadmin.PackageAdmin;
@@ -106,9 +110,6 @@
public final void run()
{
- // wait some time for the request to settle
- sleepSilently( 500L );
-
// now deploy the resolved bundles
try
{
@@ -118,15 +119,13 @@
// invalid by the time we want to call the update
PackageAdmin pa = ( refreshPackages ) ? ( PackageAdmin ) getService( PackageAdmin.class.getName() ) : null;
+ // perform the action!
Bundle bundle = doRun();
if ( pa != null && bundle != null )
{
- // wait for asynchronous bundle start tasks to finish
- sleepSilently( 2000L );
-
- pa.refreshPackages( new Bundle[]
- { bundle } );
+ // refresh packages and give it at most 5 seconds to finish
+ refreshPackages( pa, plugin.getBundle().getBundleContext(), 5000L, bundle );
}
}
catch ( Exception e )
@@ -158,15 +157,97 @@
}
- protected void sleepSilently( long msecs )
+ /**
+ * This is an utility method that issues refresh package instruction to the framework.
+ *
+ * @param packageAdmin is the package admin service obtained using the bundle context of the caller.
+ * If this is <code>null</code> no refresh packages is performed
+ * @param bundleContext of the caller. This is needed to add a framework listener.
+ * @param maxWait the maximum time to wait for the packages to be refreshed
+ * @param bundle the bundle, which packages to refresh or <code>null</code> to refresh all packages.
+ * @return true if refresh is succesfull within the given time frame
+ */
+ static boolean refreshPackages(final PackageAdmin packageAdmin,
+ final BundleContext bundleContext,
+ final long maxWait,
+ final Bundle bundle)
{
- try
+ return new RefreshPackageTask().refreshPackages( packageAdmin, bundleContext, maxWait, bundle );
+ }
+
+ static class RefreshPackageTask implements FrameworkListener
+ {
+
+ private volatile boolean refreshed = false;
+ private final Object lock = new Object();
+
+ boolean refreshPackages( final PackageAdmin packageAdmin,
+ final BundleContext bundleContext,
+ final long maxWait,
+ final Bundle bundle )
{
- Thread.sleep( msecs );
+ if (null == packageAdmin)
+ {
+ return false;
+ }
+
+ if (null == bundleContext)
+ {
+ return false;
+ }
+
+ bundleContext.addFrameworkListener(this);
+
+ if (null == bundle)
+ {
+ packageAdmin.refreshPackages(null);
+ }
+ else
+ {
+ packageAdmin.refreshPackages(new Bundle[] { bundle });
+ }
+
+ try
+ {
+ // check for spurious wait
+ long start = System.currentTimeMillis();
+ long delay = maxWait;
+ while (!refreshed && delay > 0)
+ {
+ synchronized (lock)
+ {
+ if ( !refreshed )
+ {
+ lock.wait(delay);
+ // remove the time we already waited for
+ delay = maxWait - (System.currentTimeMillis() - start);
+ }
+ }
+ }
+ }
+ catch (final InterruptedException e)
+ {
+ // just return if the thread is interrupted
+ Thread.currentThread().interrupt();
+ }
+ finally
+ {
+ bundleContext.removeFrameworkListener(this);
+ }
+ return refreshed;
}
- catch ( InterruptedException ie )
+
+ public void frameworkEvent(final FrameworkEvent e)
{
- // don't care
+ if (e.getType() == FrameworkEvent.PACKAGES_REFRESHED)
+ {
+ synchronized (lock)
+ {
+ refreshed = true;
+ lock.notifyAll();
+ }
+ }
+
}
}
}
\ No newline at end of file
diff --git a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
index 605fb09..3bd0461 100644
--- a/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
+++ b/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java
@@ -327,7 +327,8 @@
final String action = WebConsoleUtil.getParameter( req, "action" );
if ( "refreshPackages".equals( action ) )
{
- getPackageAdmin().refreshPackages( null );
+ // refresh packages and give it most 15 seconds to finish
+ BaseUpdateInstallHelper.refreshPackages( getPackageAdmin(), getBundleContext(), 15000L, null );
success = true;
}
else if ( "install".equals( action ) )
@@ -384,8 +385,8 @@
}
else if ( "refresh".equals( action ) )
{
- // refresh bundle wiring
- refresh( bundle );
+ // refresh bundle wiring and give at most 5 seconds to finish
+ BaseUpdateInstallHelper.refreshPackages( getPackageAdmin(), getBundleContext(), 5000L, bundle );
}
else if ( "update".equals( action ) )
{
@@ -406,14 +407,6 @@
}
}
- // let's wait a little bit to give the framework time
- // to process our request
- try {
- Thread.sleep(800);
- } catch (InterruptedException e) {
- // we ignore this
- }
-
// write the state only
resp.setContentType( "application/json" ); //$NON-NLS-1$
resp.setCharacterEncoding( "UTF-8" ); //$NON-NLS-1$
@@ -433,13 +426,6 @@
if ( success && null != getBundleContext() )
{
- // let's wait a little bit to give the framework time
- // to process our request
- try {
- Thread.sleep(800);
- } catch (InterruptedException e) {
- // we ignore this
- }
final String pluginRoot = ( String ) req.getAttribute( WebConsoleConstants.ATTR_PLUGIN_ROOT );
final String servicesRoot = getServicesRoot( req );
try
@@ -1456,14 +1442,6 @@
return val.toString();
}
-
- private void refresh( final Bundle bundle )
- {
- getPackageAdmin().refreshPackages( new Bundle[]
- { bundle } );
- }
-
-
private void update( final Bundle bundle )
{
UpdateHelper t = new UpdateHelper( this, bundle, false );