Author: bdelacretaz
Date: Fri Jul 10 16:21:25 2009
New Revision: 793010

URL: http://svn.apache.org/viewvc?rev=793010&view=rev
Log:
SLING-1042 - Optimize jcrinstall retry cycles

Added:
    
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/OsgiControllerStatistics.java
   (with props)
    
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounter.java
   (with props)
    
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounterImpl.java
   (with props)
Modified:
    
sling/trunk/contrib/extensions/jcrinstall/it/src/test/java/org/apache/sling/jcr/jcrinstall/it/OsgiControllerTest.java
    
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java
    
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java
    
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerTask.java
    
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java

Modified: 
sling/trunk/contrib/extensions/jcrinstall/it/src/test/java/org/apache/sling/jcr/jcrinstall/it/OsgiControllerTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/jcrinstall/it/src/test/java/org/apache/sling/jcr/jcrinstall/it/OsgiControllerTest.java?rev=793010&r1=793009&r2=793010&view=diff
==============================================================================
--- 
sling/trunk/contrib/extensions/jcrinstall/it/src/test/java/org/apache/sling/jcr/jcrinstall/it/OsgiControllerTest.java
 (original)
+++ 
sling/trunk/contrib/extensions/jcrinstall/it/src/test/java/org/apache/sling/jcr/jcrinstall/it/OsgiControllerTest.java
 Fri Jul 10 16:21:25 2009
@@ -30,12 +30,15 @@
 import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
 import java.util.Dictionary;
 import java.util.Hashtable;
 
 import org.apache.sling.osgi.installer.DictionaryInstallableData;
 import org.apache.sling.osgi.installer.OsgiController;
 import org.apache.sling.osgi.installer.OsgiControllerServices;
+import org.apache.sling.osgi.installer.OsgiControllerStatistics;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.Inject;
@@ -43,9 +46,12 @@
 import org.ops4j.pax.exam.junit.JUnit4TestRunner;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.packageadmin.PackageAdmin;
 
 /** Test the OsgiController running in the OSGi framework
  *  
@@ -55,9 +61,10 @@
  *   
  */
 @RunWith(JUnit4TestRunner.class)
-public class OsgiControllerTest {
+public class OsgiControllerTest implements FrameworkListener {
        public final static String POM_VERSION = 
System.getProperty("jcrinstall.pom.version");
        public final static String JAR_EXT = ".jar";
+       private int packageRefreshEventsCount;
        
     @Inject
     protected BundleContext bundleContext;
@@ -71,6 +78,61 @@
        return result;
     }
     
+    protected void generateBundleEvent() throws Exception {
+        // install a bundle manually to generate a bundle event
+        final File f = getTestBundle("org.apache.sling.jcr.jcrinstall.it-" + 
POM_VERSION + "-testbundle-1.0.jar");
+        final InputStream is = new FileInputStream(f);
+        Bundle b = null;
+        try {
+            b = bundleContext.installBundle(getClass().getName(), is);
+            b.start();
+            final long timeout = System.currentTimeMillis() + 2000L;
+            while(b.getState() != Bundle.ACTIVE && System.currentTimeMillis() 
< timeout) {
+                Thread.sleep(10L);
+            }
+        } finally {
+            if(is != null) {
+                is.close();
+            }
+            if(b != null) {
+                b.uninstall();
+            }
+        }
+    }
+    
+    public void frameworkEvent(FrameworkEvent event) {
+        if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
+            packageRefreshEventsCount++;
+        }
+    }
+    
+    protected void refreshPackages() {
+        bundleContext.addFrameworkListener(this);
+        final int MAX_REFRESH_PACKAGES_WAIT_SECONDS = 5;
+        final int targetEventCount = packageRefreshEventsCount + 1;
+        final long timeout = System.currentTimeMillis() + 
MAX_REFRESH_PACKAGES_WAIT_SECONDS * 1000L;
+        
+        final PackageAdmin pa = getService(PackageAdmin.class);
+        pa.refreshPackages(null);
+        
+        try {
+            while(true) {
+                if(System.currentTimeMillis() > timeout) {
+                    break;
+                }
+                if(packageRefreshEventsCount >= targetEventCount) {
+                    break;
+                }
+                try {
+                    Thread.sleep(250L);
+                } catch(InterruptedException ignore) {
+                }
+            }
+        } finally {
+            bundleContext.removeFrameworkListener(this);
+        }
+    }
+    
     protected Configuration findConfiguration(String pid) throws Exception {
        final ConfigurationAdmin ca = getService(ConfigurationAdmin.class);
        if(ca != null) {
@@ -311,6 +373,50 @@
                assertFalse(needsB + " must not be started, testB not present", 
b.getState() == Bundle.ACTIVE);
        }
        
+       // Check SLING-1042 retry rules
+       assertTrue("OsgiController must implement OsgiControllerStatistics", c 
instanceof OsgiControllerStatistics);
+       final OsgiControllerStatistics stats = (OsgiControllerStatistics)c;
+       
+       {
+           long n = stats.getExecutedTasksCount();
+           c.executeScheduledOperations();
+            assertTrue("First retry must not wait for an event", 
stats.getExecutedTasksCount() > n);
+            n = stats.getExecutedTasksCount();
+            c.executeScheduledOperations();
+           assertEquals("Retrying before a bundle event happens must not 
execute any OsgiControllerTask", n, stats.getExecutedTasksCount());
+           
+            n = stats.getExecutedTasksCount();
+           generateBundleEvent();
+            c.executeScheduledOperations();
+            assertTrue("Retrying after a bundle event must execute at least 
one OsgiControllerTask", stats.getExecutedTasksCount() > n);
+       }
+       
+       {
+           // wait until no more events are received
+            final long timeout = System.currentTimeMillis() + 2000L;
+            while(System.currentTimeMillis() < timeout) {
+                final long n = stats.getExecutedTasksCount();
+                c.executeScheduledOperations();
+                if(n == stats.getExecutedTasksCount()) {
+                    break;
+                }
+                Thread.sleep(10L);
+            }
+            
+            if(System.currentTimeMillis() >= timeout) {
+                fail("Retries did not stop within specified time");
+            }
+       }
+       
+        {
+            long n = stats.getExecutedTasksCount();
+            c.executeScheduledOperations();
+            assertEquals("Retrying before a framework event happens must not 
execute any OsgiControllerTask", n, stats.getExecutedTasksCount());
+            refreshPackages();
+            c.executeScheduledOperations();
+            assertTrue("Retrying after framework event must execute at least 
one OsgiControllerTask", stats.getExecutedTasksCount() > n);
+        }
+        
        // now install testB -> needsB must start
        {
                c.scheduleInstallOrUpdate(testB + JAR_EXT,

Added: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/OsgiControllerStatistics.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/OsgiControllerStatistics.java?rev=793010&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/OsgiControllerStatistics.java
 (added)
+++ 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/OsgiControllerStatistics.java
 Fri Jul 10 16:21:25 2009
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.installer;
+
+/** Statistics for the OsgiController */
+public interface OsgiControllerStatistics {
+    /** How many OsgiControllerTask the controller tried to execute */
+    long getExecutedTasksCount();
+}

Propchange: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/OsgiControllerStatistics.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/OsgiControllerStatistics.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java?rev=793010&r1=793009&r2=793010&view=diff
==============================================================================
--- 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java
 (original)
+++ 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/Activator.java
 Fri Jul 10 16:21:25 2009
@@ -39,14 +39,12 @@
     private static String LOG_SERVICE_NAME = LogService.class.getName();
 
     private ServiceTracker startLevelTracker;
-
     private ServiceTracker packageAdminTracker;
-
     private ServiceTracker logServiceTracker;
-
-    private OsgiControllerImpl service;
-
-    private ServiceRegistration serviceReg;
+    private OsgiControllerImpl osgiControllerService;
+    private ServiceRegistration osgiControllerServiceReg;
+    private EventsCounterImpl eventsCounter;
+    private ServiceRegistration eventsCounterServiceReg;
 
     /**
      * @see 
org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
@@ -59,21 +57,36 @@
         this.packageAdminTracker.open();
         this.logServiceTracker.open();
 
-        // register service
-        final Hashtable<String, String> props = new Hashtable<String, 
String>();
-        props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Install 
Controller Service");
-        props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+        // register OsgiController service        
+        {
+            final Hashtable<String, String> props = new Hashtable<String, 
String>();
+            props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Install 
Controller Service");
+            props.put(Constants.SERVICE_VENDOR, "The Apache Software 
Foundation");
+            
+            // Assume PackageAdmin is available before this bundle is started.
+            // That's the case when using Felix OSGi, not sure about other 
frameworks.
+            this.osgiControllerService = new OsgiControllerImpl(context,
+                    
(PackageAdmin)checkNotNull(this.packageAdminTracker.getService(), 
"PackageAdmin"),
+                    logServiceTracker);
+            final String [] serviceInterfaces = {
+                    OsgiController.class.getName(),
+                    OsgiControllerServices.class.getName()
+            };
+            osgiControllerServiceReg = 
context.registerService(serviceInterfaces, osgiControllerService, props);
+        }
         
-        // Assume PackageAdmin is available before this bundle is started.
-        // That's the case when using Felix OSGi, not sure about other 
frameworks.
-        this.service = new OsgiControllerImpl(context,
-                
(PackageAdmin)checkNotNull(this.packageAdminTracker.getService(), 
"PackageAdmin"),
-                logServiceTracker);
-        final String [] serviceInterfaces = {
-                       OsgiController.class.getName(),
-                       OsgiControllerServices.class.getName()
-        };
-        serviceReg = context.registerService(serviceInterfaces, service, 
props);
+        // register EventsCounter service        
+        {
+            final Hashtable<String, String> props = new Hashtable<String, 
String>();
+            props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling 
EventsCounter Service");
+            props.put(Constants.SERVICE_VENDOR, "The Apache Software 
Foundation");
+            
+            this.eventsCounter = new EventsCounterImpl(context);
+            final String [] serviceInterfaces = {
+                    EventsCounter.class.getName()
+            };
+            eventsCounterServiceReg = 
context.registerService(serviceInterfaces, eventsCounter, props);
+        }
     }
     
     /** Complain if value is null */
@@ -88,13 +101,21 @@
      * @see 
org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
      */
     public void stop(BundleContext context) throws Exception {
-        if ( this.serviceReg != null ) {
-            this.serviceReg.unregister();
-            this.serviceReg = null;
-        }
-        if ( this.service != null ) {
-            this.service.deactivate();
-            this.service = null;
+        if( this.eventsCounterServiceReg != null) {
+            this.eventsCounterServiceReg.unregister();
+            this.eventsCounterServiceReg = null;
+        }
+        if( this.eventsCounter != null) {
+            this.eventsCounter.deactivate();
+            this.eventsCounter = null;
+        }
+        if ( this.osgiControllerServiceReg != null ) {
+            this.osgiControllerServiceReg.unregister();
+            this.osgiControllerServiceReg = null;
+        }
+        if ( this.osgiControllerService != null ) {
+            this.osgiControllerService.deactivate();
+            this.osgiControllerService = null;
         }
         if ( this.startLevelTracker != null ) {
             this.startLevelTracker.close();

Added: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounter.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounter.java?rev=793010&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounter.java
 (added)
+++ 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounter.java
 Fri Jul 10 16:21:25 2009
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.installer.impl;
+
+/** Count framework + bundle events - used for SLING-1042 retries optimization 
*/
+public interface EventsCounter {
+    long getTotalEventsCount();
+}

Propchange: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounter.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Added: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounterImpl.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounterImpl.java?rev=793010&view=auto
==============================================================================
--- 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounterImpl.java
 (added)
+++ 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounterImpl.java
 Fri Jul 10 16:21:25 2009
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.osgi.installer.impl;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+
+/** EventsCounter implementation - simply counts events,
+ *  to avoid having to make each BundleStartTask that's
+ *  waiting for retries a FrameworkListener and BundleListener 
+ */
+class EventsCounterImpl implements EventsCounter, FrameworkListener, 
BundleListener {
+    private long eventsCount;
+    private final BundleContext bundleContext;
+    
+    EventsCounterImpl(BundleContext bc) {
+        this.bundleContext = bc;
+        bundleContext.addBundleListener(this);
+        bundleContext.addFrameworkListener(this);
+    }
+    
+    void deactivate() {
+        bundleContext.removeBundleListener(this);
+        bundleContext.removeFrameworkListener(this);
+    }
+    
+    public long getTotalEventsCount() {
+        return eventsCount;
+    }
+
+    public void frameworkEvent(FrameworkEvent arg0) {
+        // we'll retry as soon as any FrameworkEvent or BundleEvent happens
+        eventsCount++;
+    }
+
+    public void bundleChanged(BundleEvent arg0) {
+        // we'll retry as soon as any FrameworkEvent or BundleEvent happens
+        eventsCount++;
+    }
+}

Propchange: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounterImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/EventsCounterImpl.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java?rev=793010&r1=793009&r2=793010&view=diff
==============================================================================
--- 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java
 (original)
+++ 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerImpl.java
 Fri Jul 10 16:21:25 2009
@@ -29,6 +29,7 @@
 import org.apache.sling.osgi.installer.JcrInstallException;
 import org.apache.sling.osgi.installer.OsgiController;
 import org.apache.sling.osgi.installer.OsgiControllerServices;
+import org.apache.sling.osgi.installer.OsgiControllerStatistics;
 import org.apache.sling.osgi.installer.ResourceOverrideRules;
 import org.apache.sling.osgi.installer.impl.tasks.BundleInstallRemoveTask;
 import org.apache.sling.osgi.installer.impl.tasks.ConfigInstallRemoveTask;
@@ -46,7 +47,8 @@
 public class OsgiControllerImpl
     implements OsgiController,
                OsgiControllerServices,
-               OsgiControllerTaskContext {
+               OsgiControllerTaskContext,
+               OsgiControllerStatistics {
 
        private final BundleContext bundleContext;
     private final Storage storage;
@@ -59,6 +61,7 @@
     private final ServiceTracker logServiceTracker;
     private int threadCounter;
     private final PackageAdmin packageAdmin;
+    private int executedTasksCount;
 
     public static final String BUNDLE_EXTENSION = ".jar";
     public static final String STORAGE_FILENAME = "controller.storage";
@@ -144,9 +147,28 @@
         if(tasks.isEmpty()) {
                return;
         }
-
+        
+        // No executable tasks?
+        boolean exec = false;
+        synchronized (tasks) {
+            for(OsgiControllerTask t : tasks) {
+                if(t.isExecutable(this)) {
+                    exec = true;
+                    break;
+                }
+            }
+        }
+        
        if(getLogService() != null) {
-               getLogService().log(LogService.LOG_INFO, 
"executeScheduledOperations() starts");
+           if(exec) {
+                getLogService().log(LogService.LOG_INFO, 
"executeScheduledOperations() starts");
+           } else {
+                getLogService().log(LogService.LOG_DEBUG, "No executable 
tasks, nothing to do");
+           }
+       }
+       
+       if(!exec) {
+           return;
        }
        
         synchronized (tasks) {
@@ -199,6 +221,7 @@
                                        final List<OsgiControllerTask> toRemove 
= new LinkedList<OsgiControllerTask>();
                                        for(OsgiControllerTask t : tasks) {
                                                toRemove.add(t);
+                                               executedTasksCount++;
                                                executeTask(t);
                                                
if(!tasksForThisCycle.isEmpty()) {
                                                        break;
@@ -272,4 +295,7 @@
                return this;
        }
 
+       public long getExecutedTasksCount() {
+           return executedTasksCount;
+       }
 }
\ No newline at end of file

Modified: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerTask.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerTask.java?rev=793010&r1=793009&r2=793010&view=diff
==============================================================================
--- 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerTask.java
 (original)
+++ 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/OsgiControllerTask.java
 Fri Jul 10 16:21:25 2009
@@ -26,9 +26,15 @@
        /** Tasks are sorted according to this key */
        public abstract String getSortKey();
 
+       /** All comparisons are based on getSortKey() */
        public final int compareTo(OsgiControllerTask o) {
                return getSortKey().compareTo(o.getSortKey());
        }
+       
+       /** Is it worth executing this task now? */
+       public boolean isExecutable(OsgiControllerTaskContext ctx) throws 
Exception {
+           return true;
+       }
 
        @Override
        public final boolean equals(Object o) {

Modified: 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java?rev=793010&r1=793009&r2=793010&view=diff
==============================================================================
--- 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java
 (original)
+++ 
sling/trunk/contrib/extensions/jcrinstall/osgi/src/main/java/org/apache/sling/osgi/installer/impl/tasks/BundleStartTask.java
 Fri Jul 10 16:21:25 2009
@@ -20,10 +20,14 @@
 
 import java.text.DecimalFormat;
 
+import org.apache.sling.osgi.installer.JcrInstallException;
+import org.apache.sling.osgi.installer.impl.EventsCounter;
 import org.apache.sling.osgi.installer.impl.OsgiControllerTask;
 import org.apache.sling.osgi.installer.impl.OsgiControllerTaskContext;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.log.LogService;
 
 /** Task that starts a bundle */
@@ -31,6 +35,8 @@
 
        private final long bundleId;
        private final String sortKey;
+       private long eventsCountForRetrying;
+       private int retryCount = 0;
        
        public BundleStartTask(long bundleId) {
                this.bundleId = bundleId;
@@ -50,6 +56,7 @@
        public void execute(OsgiControllerTaskContext tctx) throws Exception {
                final Bundle b = tctx.getBundleContext().getBundle(bundleId);
                final LogService log = 
tctx.getOsgiControllerServices().getLogService();
+               boolean needToRetry = false;
                
                if(b == null) {
                        if(log != null) {
@@ -58,24 +65,70 @@
                        return;
                }
                
-               if(b.getState() == Bundle.ACTIVE) {
-                       if(log != null) {
-                               log.log(LogService.LOG_DEBUG, "Bundle already 
started, no action taken:" + bundleId + "/" + b.getSymbolicName());
-                       }
-               } else {
-                       try {
-                               b.start();
-                               if(log != null) {
-                                       log.log(LogService.LOG_INFO, "Bundle 
started:" + bundleId + "/" + b.getSymbolicName());
-                               }
-                       } catch(BundleException e) {
-                               if(log != null) {
-                                       log.log(LogService.LOG_INFO, 
-                                                       "Could not start bundle 
(" + e + "), will retry: " + bundleId + "/" + b.getSymbolicName());
-                               }
-                               tctx.addTaskToNextCycle(this);
-                       }
-                       
+               try {
+               if(b.getState() == Bundle.ACTIVE) {
+                   if(log != null) {
+                       log.log(LogService.LOG_DEBUG, "Bundle already started, 
no action taken:" + bundleId + "/" + b.getSymbolicName());
+                   }
+               } else {
+                   // Try to start bundle, and if that doesn't work we'll need 
to retry
+                   try {
+                       b.start();
+                       if(log != null) {
+                           log.log(LogService.LOG_INFO, 
+                                   "Bundle started (retry count=" + retryCount 
+ ", bundle ID=" + bundleId + ") " + b.getSymbolicName());
+                       }
+                   } catch(BundleException e) {
+                       if(log != null) {
+                           log.log(LogService.LOG_INFO, 
+                                   "Could not start bundle (retry count=" + 
retryCount + ", " + e 
+                                   + "), will retry: " + bundleId + "/" + 
b.getSymbolicName());
+                       }
+                       needToRetry = true;
+                   }
+                   
+               }
+               } finally {
+               if(needToRetry) {
+                   
+                   // Do the first retry immediately (in case "something" 
happenened right now
+                   // that warrants a retry), but for the next ones wait for 
at least one bundle
+                   // event or framework event
+                   if(retryCount == 0) {
+                       eventsCountForRetrying = 
getEventsCount(tctx.getBundleContext());
+                   } else {
+                    eventsCountForRetrying = 
getEventsCount(tctx.getBundleContext()) + 1;
+                   }
+                   
+                   tctx.addTaskToNextCycle(this);
+               }
                }
+               retryCount++;
        }
+       
+       /** Do not execute this task if waiting for events */
+    public boolean isExecutable(OsgiControllerTaskContext tctx) throws 
JcrInstallException {
+        final long eventsCount = getEventsCount(tctx.getBundleContext()); 
+        final boolean result = eventsCount >= eventsCountForRetrying; 
+        if(!result) {
+            if(tctx.getOsgiControllerServices().getLogService() != null) {
+                
tctx.getOsgiControllerServices().getLogService().log(LogService.LOG_DEBUG, 
+                        this + " is not executable at this time, counters=" + 
eventsCountForRetrying + "/" + eventsCount);
+            }
+        }
+        return result;
+    }
+    
+    /** Return current events count */
+    protected long getEventsCount(BundleContext bc) throws JcrInstallException 
{
+        final ServiceReference sr = 
bc.getServiceReference(EventsCounter.class.getName());
+        if(sr == null) {
+            throw new JcrInstallException("EventsCounter service not found");
+        }
+        final EventsCounter ec = (EventsCounter)bc.getService(sr);
+        if(ec == null) {
+            throw new JcrInstallException("EventsCounter service not found, 
although its ServiceReference was found");
+        }
+        return ec.getTotalEventsCount();
+    }
 }


Reply via email to