You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by ff...@apache.org on 2012/10/25 03:34:47 UTC

svn commit: r1401944 - in /karaf/branches/karaf-2.3.x/main/src: main/java/org/apache/karaf/main/ test/java/org/apache/karaf/main/

Author: ffang
Date: Thu Oct 25 01:34:46 2012
New Revision: 1401944

URL: http://svn.apache.org/viewvc?rev=1401944&view=rev
Log:
[KARAF-1938]Lock logic should wait for start level change to occur 

Added:
    karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/StartLevelListener.java
    karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MainLockingTest.java
    karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MockLock.java
Modified:
    karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/Main.java

Modified: karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/Main.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/Main.java?rev=1401944&r1=1401943&r2=1401944&view=diff
==============================================================================
--- karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/Main.java (original)
+++ karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/Main.java Thu Oct 25 01:34:46 2012
@@ -51,6 +51,7 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
 import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.launch.Framework;
 import org.osgi.framework.launch.FrameworkFactory;
@@ -210,7 +211,8 @@ public class Main {
     private boolean exiting = false;
     private ShutdownCallback shutdownCallback;
     private List<BundleActivator> karafActivators = new ArrayList<BundleActivator>();
-
+    private Object startLevelLock = new Object();
+    private StartLevelListener startLevelListener;
 
     public Main(String[] args) {
         this.args = args;
@@ -290,6 +292,10 @@ public class Main {
         // Process properties
         loadStartupProperties(configProps);
         processAutoProperties(framework.getBundleContext());
+
+        startLevelListener = new StartLevelListener(startLevelLock);
+        framework.getBundleContext().addFrameworkListener(startLevelListener);
+
         framework.start();
         // Start custom activators
         startKarafActivators(classLoader);
@@ -1370,8 +1376,16 @@ public class Main {
                     Thread.sleep(lockDelay);
                 }
                 if (framework.getState() == Bundle.ACTIVE && !exiting) {
-                    LOG.info("Lost the lock, stopping this instance ...");
-                    setStartLevel(lockStartLevel);
+                    LOG.info("Lost the lock, reducing start level to " + lockStartLevel);
+                    synchronized (startLevelLock) {
+                        setStartLevel(lockStartLevel);
+                        
+                        // we have to wait for the start level to be reduced here because
+                        // if the lock is regained before the start level is fully changed
+                        // things may not come up as expected
+                        LOG.fine("Waiting for start level change to complete...");
+                        startLevelLock.wait(shutdownTimeout);
+                    }
                 }
             } else if (!lockLogged) {
                 LOG.info("Waiting for the lock ...");
@@ -1444,6 +1458,10 @@ public class Main {
         }
     }
 
+    public Lock getLock() {
+        return lock;
+    }
+
     private class ShutdownSocketThread extends Thread {
 
         private final String shutdown;

Added: karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/StartLevelListener.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/StartLevelListener.java?rev=1401944&view=auto
==============================================================================
--- karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/StartLevelListener.java (added)
+++ karaf/branches/karaf-2.3.x/main/src/main/java/org/apache/karaf/main/StartLevelListener.java Thu Oct 25 01:34:46 2012
@@ -0,0 +1,43 @@
+/*
+ * 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.karaf.main;
+
+import java.util.logging.Logger;
+
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+
+public class StartLevelListener implements FrameworkListener {
+
+    Logger LOG = Logger.getLogger(this.getClass().getName());
+    private Object startLevelLock;
+    
+    public StartLevelListener(Object startLevelLock) {
+        this.startLevelLock = startLevelLock;
+    }
+
+    public void frameworkEvent(FrameworkEvent event) {
+        if (event.getType() == FrameworkEvent.STARTLEVEL_CHANGED) {
+            synchronized (startLevelLock) {
+                LOG.fine("Start level change complete.");
+                startLevelLock.notifyAll();
+            }
+        }
+    }
+}

Added: karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MainLockingTest.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MainLockingTest.java?rev=1401944&view=auto
==============================================================================
--- karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MainLockingTest.java (added)
+++ karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MainLockingTest.java Thu Oct 25 01:34:46 2012
@@ -0,0 +1,100 @@
+/*
+ * 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.karaf.main;
+
+import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.withBnd;
+
+import java.io.File;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.ops4j.pax.swissbox.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.launch.Framework;
+import org.osgi.service.startlevel.StartLevel;
+
+public class MainLockingTest {
+    
+    @Test
+    public void testLostMasterLock() throws Exception {
+        File basedir = new File(getClass().getClassLoader().getResource("foo").getPath()).getParentFile();
+        File home = new File(basedir, "test-karaf-home");
+        File data = new File(home, "data");
+
+        Utils.deleteDirectory(data);
+
+        String[] args = new String[0];
+        System.setProperty("karaf.home", home.toString());
+        System.setProperty("karaf.data", data.toString());
+        System.setProperty("karaf.framework.factory", "org.apache.felix.framework.FrameworkFactory");
+        
+        // enable locking
+        System.setProperty("karaf.lock","true");
+        System.setProperty("karaf.lock.delay","1000");
+        System.setProperty("karaf.lock.class","org.apache.karaf.main.MockLock");
+
+        Main main = new Main(args);
+        main.launch();
+        Thread.sleep(1000);
+        
+        Framework framework = main.getFramework();
+        String activatorName = TimeoutShutdownActivator.class.getName().replace('.', '/') + ".class";
+        Bundle bundle = framework.getBundleContext().installBundle("foo",
+                TinyBundles.newBundle()
+                    .set( Constants.BUNDLE_ACTIVATOR, TimeoutShutdownActivator.class.getName() )
+                    .add( activatorName, getClass().getClassLoader().getResourceAsStream( activatorName ) )
+                    .build( withBnd() )
+        );
+        bundle.start();       
+        
+        BundleContext ctx = framework.getBundleContext();
+        ServiceReference[] refs = ctx.getServiceReferences(StartLevel.class.getName(), null);
+        StartLevel sl = (StartLevel) ctx.getService(refs[0]);
+
+        MockLock lock = (MockLock) main.getLock();
+
+        Assert.assertEquals(100, sl.getStartLevel());       
+
+        // simulate losing a lock
+        lock.setIsAlive(false);
+        lock.setLock(false);
+        
+        // lets wait until the start level change is complete
+        lock.waitForLock();
+        Assert.assertEquals(1, sl.getStartLevel());
+
+        Thread.sleep(1000);
+        
+        // get lock back
+        lock.setIsAlive(true);
+        lock.setLock(true);
+
+        // wait for loop to recognize lock
+        lock.waitForLock();
+        
+        Thread.sleep(1000);
+        
+        // exit framework + lock loop
+        main.destroy();
+    }    
+}

Added: karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MockLock.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MockLock.java?rev=1401944&view=auto
==============================================================================
--- karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MockLock.java (added)
+++ karaf/branches/karaf-2.3.x/main/src/test/java/org/apache/karaf/main/MockLock.java Thu Oct 25 01:34:46 2012
@@ -0,0 +1,64 @@
+package org.apache.karaf.main;
+
+import java.util.Properties;
+import java.util.logging.Logger;
+
+/*
+ * 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.
+ */
+public class MockLock implements Lock {
+
+    private boolean lock = true;
+    private boolean isAlive = true; 
+    private static final Logger LOG = Logger.getLogger(MockLock.class.getName());
+    private Object lockLock = new Object();
+    
+    public MockLock(Properties props) {
+    }
+    
+    public boolean lock() throws Exception {
+        synchronized (lockLock) {
+            LOG.fine("lock = " + lock);        
+            lockLock.notifyAll();
+        }
+        return lock;
+    }
+
+    public void release() throws Exception {
+        LOG.fine("release");
+    }
+
+    public boolean isAlive() throws Exception {
+        LOG.fine("isAlive = " + isAlive);
+        return isAlive;
+    }
+
+    public void setLock(boolean lock) {
+        this.lock = lock;
+    }
+
+    public void setIsAlive(boolean isAlive) {
+        this.isAlive = isAlive;
+    }
+    
+    public void waitForLock() throws InterruptedException {
+        synchronized (lockLock) {
+            lockLock.wait(1000 * 60 * 5);
+        }
+    }
+}