From d1b0777dc2986ac34432278e61ca920de7592afc Mon Sep 17 00:00:00 2001 From: Jochen Hiller Date: Mon, 12 Dec 2022 14:26:01 +0100 Subject: [PATCH 1/6] Added test case for FELIX-6586 along Felix style of test cases --- .../FrameworkStartLevelImplTest.java | 288 ++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java diff --git a/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java new file mode 100644 index 0000000000..478c0386fa --- /dev/null +++ b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java @@ -0,0 +1,288 @@ +/* +How to test: + +git clone -b feature/test-startlevel-impl https://github.com/JochenHiller/felix-dev +cd felix-dev +cd framework +mvn clean compile +mvn test -Dtest=FrameworkStartLevelImplTest + +See as well: +* https://issues.apache.org/jira/browse/FELIX-6586 + +*/ + +package org.apache.felix.framework; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; + +import junit.framework.TestCase; + +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.launch.Framework; +import org.osgi.framework.startlevel.BundleStartLevel; +import org.osgi.framework.startlevel.FrameworkStartLevel; + +import static org.osgi.framework.Constants.SYSTEM_BUNDLE_ID; + +public class FrameworkStartLevelImplTest extends TestCase { + + /** + * This test will install 3 bundles A, B, C. They have to be started due to + * start + * levels in order of C, B, A. + */ + public void testStartLevelStraight() throws Exception { + File tmpDir = createTmpDir("generated-bundles"); + File cacheDir = createTmpDir("felix-cache"); + File fileA = createBundle("A", tmpDir, TestNoisyBundleActivator.class); + File fileB = createBundle("B", tmpDir, TestNoisyBundleActivator.class); + File fileC = createBundle("C", tmpDir, TestNoisyBundleActivator.class); + + Framework framework = createFramework(cacheDir); + framework.init(); + framework.start(); + FrameworkStartLevel frameworkStartLevel = framework.adapt(FrameworkStartLevel.class); + frameworkStartLevel.setStartLevel(1); + + Bundle bundleA = framework.getBundleContext().installBundle(fileA.toURI().toString()); + BundleStartLevel bundleAStartLevel = bundleA.adapt(BundleStartLevel.class); + bundleAStartLevel.setStartLevel(40); + bundleA.start(); + + Bundle bundleB = framework.getBundleContext().installBundle(fileB.toURI().toString()); + BundleStartLevel bundleBStartLevel = bundleB.adapt(BundleStartLevel.class); + bundleBStartLevel.setStartLevel(30); + bundleB.start(); + + Bundle bundleC = framework.getBundleContext().installBundle(fileC.toURI().toString()); + BundleStartLevel bundleCStartLevel = bundleC.adapt(BundleStartLevel.class); + bundleCStartLevel.setStartLevel(20); + bundleC.start(); + + frameworkStartLevel.setStartLevel(100); + + Thread.sleep(1000); + + framework.stop(); + deleteTmpDir(cacheDir); + deleteTmpDir(tmpDir); + + Thread.sleep(1000); + } + + /** + * This test will install 4 bundles A, B, C, M. Bundles A, B, C will have an + * initial start level of 11. + * Bundle M (start level 10) manipulates start levels in activator for Bundles + * A, B, C that + * start order should be C, B, A. + */ + public void testStartLevelManipulatedByBundle() throws Exception { + int initialBundleStartLevel = 11; // 11, 21, 31 does fail, >40 does work + + File tmpDir = createTmpDir("generated-bundles"); + File cacheDir = createTmpDir("felix-cache"); + File fileA = createBundle("A", tmpDir, TestNoisyBundleActivator.class); + File fileB = createBundle("B", tmpDir, TestNoisyBundleActivator.class); + File fileC = createBundle("C", tmpDir, TestNoisyBundleActivator.class); + File fileM = createBundle("M", tmpDir, TestManipulatingBundleActivator.class); + + Framework framework = createFramework(cacheDir); + framework.init(); + framework.start(); + FrameworkStartLevel frameworkStartLevel = framework.adapt(FrameworkStartLevel.class); + frameworkStartLevel.setStartLevel(1); + + Bundle bundleA = framework.getBundleContext().installBundle(fileA.toURI().toString()); + BundleStartLevel bundleAStartLevel = bundleA.adapt(BundleStartLevel.class); + bundleAStartLevel.setStartLevel(initialBundleStartLevel); + bundleA.start(); + + Bundle bundleB = framework.getBundleContext().installBundle(fileB.toURI().toString()); + BundleStartLevel bundleBStartLevel = bundleB.adapt(BundleStartLevel.class); + bundleBStartLevel.setStartLevel(initialBundleStartLevel); + bundleB.start(); + + Bundle bundleC = framework.getBundleContext().installBundle(fileC.toURI().toString()); + BundleStartLevel bundleCStartLevel = bundleC.adapt(BundleStartLevel.class); + bundleCStartLevel.setStartLevel(initialBundleStartLevel); + bundleC.start(); + + Bundle bundleM = framework.getBundleContext().installBundle(fileM.toURI().toString()); + BundleStartLevel bundleMStartLevel = bundleM.adapt(BundleStartLevel.class); + bundleMStartLevel.setStartLevel(10); + bundleM.start(); + + frameworkStartLevel.setStartLevel(100); + + Thread.sleep(1000); + + framework.stop(); + deleteTmpDir(cacheDir); + deleteTmpDir(tmpDir); + + Thread.sleep(1000); + } + + // helper methods + + private File createTmpDir(String prefix) throws IOException { + File tmpDir = File.createTempFile(prefix, ".dir"); + // System.out.println("tmpDir=" + tmpDir); + + // File tmpDir = new File("./" + prefix); // use to check bundle content locally + // in workspace + + deleteTmpDir(tmpDir); + tmpDir.mkdirs(); + return tmpDir; + } + + private void deleteTmpDir(File tmpDir) throws IOException { + if (tmpDir.isDirectory()) { + for (File file : tmpDir.listFiles()) { + deleteTmpDir(file); + } + } + tmpDir.delete(); + assertFalse(tmpDir.exists()); + } + + private Framework createFramework(File cacheDir) { + final String cacheDirPath = cacheDir.getPath(); + final Map params = new HashMap(); + // OSGi R8 + StartLevels + params.put(Constants.FRAMEWORK_SYSTEMPACKAGES, + "org.osgi.framework; version=1.10.0," + + "org.osgi.framework.startlevel; version=1.0.0"); + params.put("felix.cache.profiledir", cacheDirPath); + params.put("felix.cache.dir", cacheDirPath); + params.put(Constants.FRAMEWORK_STORAGE, cacheDirPath); + + Framework framework = new Felix(params); + return framework; + } + + private File createBundle(String bundleName, File dir, Class activatorClass) throws IOException { + String mf = "Bundle-SymbolicName: " + bundleName + "\n" + + "Bundle-Version: 1.0.0\n" + + "Bundle-ManifestVersion: 2\n" + + "Import-Package: org.osgi.framework; version=\"[1.10,2.0)\"," + + "org.osgi.framework.startlevel; version=\"[1.0,2.0)\"\n"; + File bundleFile = createBundle(bundleName, mf, dir, activatorClass); + return bundleFile; + } + + private File createBundle(String bundleName, String manifest, File tmpDir, Class activatorClass) + throws IOException { + File f = File.createTempFile("bundle" + bundleName + "-", ".jar", tmpDir); + + Manifest mf = new Manifest(new ByteArrayInputStream(manifest.getBytes("utf-8"))); + mf.getMainAttributes().putValue("Manifest-Version", "1.0"); + mf.getMainAttributes().putValue(Constants.BUNDLE_ACTIVATOR, activatorClass.getName()); + JarOutputStream os = new JarOutputStream(new FileOutputStream(f), mf); + + String path = activatorClass.getName().replace('.', '/') + ".class"; + os.putNextEntry(new ZipEntry(path)); + + InputStream is = activatorClass.getClassLoader().getResourceAsStream(path); + byte[] b = new byte[is.available()]; + is.read(b); + is.close(); + os.write(b); + + os.close(); + return f; + } + + public static class TestManipulatingBundleActivator implements BundleActivator { + public void start(BundleContext context) throws Exception { + dumpState(context, "start"); + manipulateStartLevel(context, "A", 40); + manipulateStartLevel(context, "B", 30); + manipulateStartLevel(context, "C", 20); + } + + public void stop(BundleContext context) throws Exception { + dumpState(context, "stop"); + } + + private void manipulateStartLevel(BundleContext context, String bsn, int newStartLevel) { + Bundle framework = context.getBundle(SYSTEM_BUNDLE_ID); + + for (Bundle b : context.getBundles()) { + if (bsn.equals(b.getSymbolicName())) { + BundleStartLevel bundleStartLevel = b.adapt(BundleStartLevel.class); + int oldStartLevel = bundleStartLevel.getStartLevel(); + bundleStartLevel.setStartLevel(newStartLevel); + System.out.print("Bundle " + b.toString() + ": manipulateStartLevel() ==> "); + System.out.print("bundleStartLevel: old: " + + oldStartLevel + ", new: " + newStartLevel + ", "); + + FrameworkStartLevel frameworkStartLevel = framework.adapt(FrameworkStartLevel.class); + System.out.print("frameworkStartLevel: " + + frameworkStartLevel.getStartLevel() + ", "); + System.out.print("initialBundleStartLevel: " + + frameworkStartLevel.getInitialBundleStartLevel() + ", "); + System.out.println(); + } + } + } + + private void dumpState(BundleContext context, String method) { + Bundle bundle = context.getBundle(); + System.out.print("Bundle " + bundle.toString() + ": " + method + "() ==> "); + BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class); + System.out.print("bundleStartLevel: " + + bundleStartLevel.getStartLevel() + ", "); + + Bundle framework = context.getBundle(SYSTEM_BUNDLE_ID); + FrameworkStartLevel frameworkStartLevel = framework.adapt(FrameworkStartLevel.class); + System.out.print("frameworkStartLevel: " + + frameworkStartLevel.getStartLevel() + ", "); + System.out.print("initialBundleStartLevel: " + + frameworkStartLevel.getInitialBundleStartLevel() + ", "); + System.out.println(); + } + + } + + public static class TestNoisyBundleActivator implements BundleActivator { + public void start(BundleContext context) throws Exception { + dumpState(context, "start"); + } + + public void stop(BundleContext context) throws Exception { + dumpState(context, "stop"); + } + + private void dumpState(BundleContext context, String method) { + Bundle bundle = context.getBundle(); + System.out.print("Bundle " + bundle.toString() + ": " + method + "() ==> "); + BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class); + System.out.print("bundleStartLevel: " + + bundleStartLevel.getStartLevel() + ", "); + + Bundle framework = context.getBundle(SYSTEM_BUNDLE_ID); + FrameworkStartLevel frameworkStartLevel = framework.adapt(FrameworkStartLevel.class); + System.out.print("frameworkStartLevel: " + + frameworkStartLevel.getStartLevel() + ", "); + System.out.print("initialBundleStartLevel: " + + frameworkStartLevel.getInitialBundleStartLevel() + ", "); + System.out.println(); + } + } +} From bbd23a5b5462ae9b6ffe059645e48c834a9acaff Mon Sep 17 00:00:00 2001 From: Jochen Hiller Date: Mon, 12 Dec 2022 14:57:31 +0100 Subject: [PATCH 2/6] Added Apache License header, changed default start level to 12 to indicate it does not need to be 10+1 --- .../FrameworkStartLevelImplTest.java | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java index 478c0386fa..537b743edc 100644 --- a/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java +++ b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java @@ -1,17 +1,21 @@ /* -How to test: - -git clone -b feature/test-startlevel-impl https://github.com/JochenHiller/felix-dev -cd felix-dev -cd framework -mvn clean compile -mvn test -Dtest=FrameworkStartLevelImplTest - -See as well: -* https://issues.apache.org/jira/browse/FELIX-6586 - -*/ - + * 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.felix.framework; import java.io.ByteArrayInputStream; @@ -91,7 +95,7 @@ public void testStartLevelStraight() throws Exception { * start order should be C, B, A. */ public void testStartLevelManipulatedByBundle() throws Exception { - int initialBundleStartLevel = 11; // 11, 21, 31 does fail, >40 does work + int initialBundleStartLevel = 12; // 12, 25, 37 does fail, >40 does work File tmpDir = createTmpDir("generated-bundles"); File cacheDir = createTmpDir("felix-cache"); From c97326341a2eca3e88b2f2c074d9db744a2615de Mon Sep 17 00:00:00 2001 From: Jochen Hiller Date: Fri, 16 Dec 2022 15:51:44 +0100 Subject: [PATCH 3/6] Added debug messages to analyze the problem, added assertions to test --- .../org/apache/felix/framework/Felix.java | 32 +++++++ .../framework/FrameworkStartLevelImpl.java | 26 +++++- .../FrameworkStartLevelImplTest.java | 87 +++++++++++++++++-- 3 files changed, 137 insertions(+), 8 deletions(-) diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java index 85cce9984e..99cbca7664 100644 --- a/framework/src/main/java/org/apache/felix/framework/Felix.java +++ b/framework/src/main/java/org/apache/felix/framework/Felix.java @@ -110,6 +110,18 @@ public class Felix extends BundleImpl implements Framework { + // poor mans debugging + static final boolean SHOW_DEBUG = true; + static void debug(String msg) { + debug("[Felix]", msg); + } + static void debug(String className, String msg) { + if (! SHOW_DEBUG) return; + String thread = Thread.currentThread().toString().substring(6); + String logMsg = String.format("%-25s %-25s %s", thread, className, msg); + System.out.println(logMsg); + } + // The secure action used to do privileged calls static final SecureAction m_secureAction = new SecureAction(); @@ -180,6 +192,13 @@ public class Felix extends BundleImpl implements Framework private final SortedSet m_startLevelBundles = new TreeSet(); + private void debugStartLevelBundles(String msg) { + debug("dumpStartLevelBundles: " + msg); + for (StartLevelTuple t : m_startLevelBundles) { + debug(" tuple: " + t); + } + } + // Local bundle cache. private BundleCache m_cache = null; @@ -1466,6 +1485,7 @@ void setActiveStartLevel(int requestedLevel, FrameworkListener[] listeners) (BundleImpl) b, ((BundleImpl) b).getStartLevel( getInitialBundleStartLevel()))); + debugStartLevelBundles("setActiveStartLevel: m_startLevelBundles.added bundle " + b.toString()); } bundlesRemaining = !m_startLevelBundles.isEmpty(); } @@ -1510,6 +1530,9 @@ void setActiveStartLevel(int requestedLevel, FrameworkListener[] listeners) } } + debug("setActiveStartLevel: process next tuple: " + tuple + + ", m_activeStartLevel: " + m_activeStartLevel); + // Ignore the system bundle, since its start() and // stop() methods get called explicitly in Felix.start() // and Felix.stop(), respectively. @@ -1537,6 +1560,7 @@ void setActiveStartLevel(int requestedLevel, FrameworkListener[] listeners) synchronized (m_startLevelBundles) { m_startLevelBundles.remove(tuple); + debugStartLevelBundles("setActiveStartLevel: m_startLevelBundles.removed " + tuple.toString()); bundlesRemaining = !m_startLevelBundles.isEmpty(); } } @@ -1602,6 +1626,7 @@ else if (isLowering synchronized (m_startLevelBundles) { m_startLevelBundles.remove(tuple); + debugStartLevelBundles("setActiveStartLevel: m_startLevelBundles.remove tuple " + tuple.toString()); bundlesRemaining = !m_startLevelBundles.isEmpty(); } } @@ -2217,6 +2242,8 @@ else if (bundleLevel > m_targetStartLevel) // queued but processed synchronously. // Note: Don't queue starts from the start level thread, otherwise // we'd never get anything started. + debug("startBundle: bundle: " + bundle.getSymbolicName() + ", level: " + bundleLevel + + ", check thread: " + Thread.currentThread().getName()+ ", fw: " + FrameworkStartLevelImpl.THREAD_NAME); if (!Thread.currentThread().getName().equals(FrameworkStartLevelImpl.THREAD_NAME)) { synchronized (m_startLevelBundles) @@ -2263,6 +2290,7 @@ else if (bundleLevel > m_targetStartLevel) if (!found) { m_startLevelBundles.add(new StartLevelTuple(bundle, bundleLevel)); + debugStartLevelBundles("startBundle: m_startLevelBundles.added bundle " + bundle + ", " + bundleLevel); } // Note that although we queued the transiently started @@ -5395,6 +5423,10 @@ else if (m_bundle.getBundleId() == t.m_bundle.getBundleId()) return result; } + + public String toString() { + return "StartLevelTuple(" + m_bundle + ", " + m_level + ")"; + } } // diff --git a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java index 53a8d7e318..cfef2b92fb 100644 --- a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java +++ b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java @@ -32,6 +32,11 @@ class FrameworkStartLevelImpl implements FrameworkStartLevel, Runnable { + // poor mans debugging + static void debug(String msg) { + Felix.debug("[FrameworkStartLevelImpl]", msg); + } + static final String THREAD_NAME = "FelixStartLevel"; private final Felix m_felix; @@ -64,6 +69,7 @@ private void startThread() m_thread = new Thread(this, THREAD_NAME); m_thread.setDaemon(true); m_thread.start(); + debug("startThread: thread started"); } } @@ -88,6 +94,7 @@ void stop() // Wake up the thread, if it is currently in the wait() state // for more work. + debug ("stop: m_requests.notifyAll"); m_requests.notifyAll(); } } @@ -126,7 +133,12 @@ public void setStartLevel(int startlevel, FrameworkListener... listeners) throw new IllegalStateException("No inital startlevel yet"); } // Queue request. - m_requests.add(new StartLevelRequest(null, startlevel, listeners)); + // m_requests.add(new StartLevelRequest(null, startlevel, listeners)); + StartLevelRequest request = new StartLevelRequest(null, startlevel, listeners); + m_requests.add(request); + debug("setStartLevel: m_requests.added request: " + request); + + debug ("setStartLevel: m_requests.notifyAll"); m_requests.notifyAll(); } } @@ -148,11 +160,13 @@ public void setStartLevel(int startlevel, FrameworkListener... listeners) startThread(); // Queue request. m_requests.add(request); + debug("setStartLevelAndWait: m_requests.added: request: " + request); m_requests.notifyAll(); } try { + debug("setStartLevelAndWait: request.wait"); request.wait(); } catch (InterruptedException ex) @@ -261,16 +275,19 @@ public void run() synchronized (m_requests) { // Wait for a request. + debug("run: m_requests.size: " + m_requests.size()); while (m_requests.isEmpty()) { // Terminate the thread if requested to do so (see stop()). if (m_thread == null) { + debug("run: thread stopped"); return; } try { + debug("run: m_requests.wait"); m_requests.wait(); } catch (InterruptedException ex) @@ -281,6 +298,7 @@ public void run() // Get the requested start level. request = m_requests.remove(0); + debug("run: m_requests.remove request: " + request); } // If the request object has no bundle, then the request @@ -310,6 +328,7 @@ public void run() synchronized (m_requests) { m_requests.add(0, request); + debug("run: m_requests.added request: " + request); previousRequest = request; } } @@ -328,6 +347,7 @@ public void run() // Notify any waiting thread that this request is done. synchronized (request) { + debug("run: request.notifyAll"); request.notifyAll(); } } @@ -364,5 +384,9 @@ public FrameworkListener[] getListeners() { return m_listeners; } + + public String toString() { + return "StartLevelRequest(" + m_bundle + ", " + m_startLevel + ")"; + } } } diff --git a/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java index 537b743edc..f10211b8c3 100644 --- a/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java +++ b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java @@ -19,10 +19,12 @@ package org.apache.felix.framework; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.PrintStream; import java.util.HashMap; import java.util.Map; import java.util.jar.JarOutputStream; @@ -41,6 +43,18 @@ import static org.osgi.framework.Constants.SYSTEM_BUNDLE_ID; +/* +How to test: + +git clone -b feature/test-startlevel-impl https://github.com/JochenHiller/felix-dev +cd felix-dev +cd framework +mvn clean compile +mvn test -Dtest=FrameworkStartLevelImplTest + +See as well: +* https://issues.apache.org/jira/browse/FELIX-6586 +*/ public class FrameworkStartLevelImplTest extends TestCase { /** @@ -49,6 +63,8 @@ public class FrameworkStartLevelImplTest extends TestCase { * levels in order of C, B, A. */ public void testStartLevelStraight() throws Exception { + redirectSystemOut(); + File tmpDir = createTmpDir("generated-bundles"); File cacheDir = createTmpDir("felix-cache"); File fileA = createBundle("A", tmpDir, TestNoisyBundleActivator.class); @@ -84,7 +100,18 @@ public void testStartLevelStraight() throws Exception { deleteTmpDir(cacheDir); deleteTmpDir(tmpDir); - Thread.sleep(1000); + restoreSystemOut(); + + System.out.println(getSystemOut()); // enable on demand + + String[] lines = getSystemOutAsArray(); + + assertTrue(lines[0].startsWith("Bundle C [3]: start() ==> bundleStartLevel: 20, frameworkStartLevel: 20")); + assertTrue(lines[1].startsWith("Bundle B [2]: start() ==> bundleStartLevel: 30, frameworkStartLevel: 30")); + assertTrue(lines[2].startsWith("Bundle A [1]: start() ==> bundleStartLevel: 40, frameworkStartLevel: 40")); + assertTrue(lines[3].startsWith("Bundle A [1]: stop() ==> bundleStartLevel: 40, frameworkStartLevel: 40")); + assertTrue(lines[4].startsWith("Bundle B [2]: stop() ==> bundleStartLevel: 30, frameworkStartLevel: 30")); + assertTrue(lines[5].startsWith("Bundle C [3]: stop() ==> bundleStartLevel: 20, frameworkStartLevel: 20")); } /** @@ -95,6 +122,8 @@ public void testStartLevelStraight() throws Exception { * start order should be C, B, A. */ public void testStartLevelManipulatedByBundle() throws Exception { + redirectSystemOut(); + int initialBundleStartLevel = 12; // 12, 25, 37 does fail, >40 does work File tmpDir = createTmpDir("generated-bundles"); @@ -132,17 +161,65 @@ public void testStartLevelManipulatedByBundle() throws Exception { frameworkStartLevel.setStartLevel(100); - Thread.sleep(1000); + Thread.sleep(100); // give chance to startup framework.stop(); deleteTmpDir(cacheDir); deleteTmpDir(tmpDir); - Thread.sleep(1000); + restoreSystemOut(); + + System.out.println(getSystemOut()); // enable on demand + + String[] lines = getSystemOutAsArray(); + assertTrue(lines[0].startsWith("Bundle M [4]: start() ==> bundleStartLevel: 10")); + + // @formatter:off + // Bundle A [1]: manipulateStartLevel() ==> bundleStartLevel: old: 12, new: 40, frameworkStartLevel: 10, + // Bundle B [2]: manipulateStartLevel() ==> bundleStartLevel: old: 12, new: 30, frameworkStartLevel: 10, + // Bundle C [3]: manipulateStartLevel() ==> bundleStartLevel: old: 12, new: 20, frameworkStartLevel: 10, + // @formatter:on + + assertTrue(lines[4].startsWith("Bundle C [3]: start() ==> bundleStartLevel: 20, frameworkStartLevel: 20")); + assertTrue(lines[5].startsWith("Bundle B [2]: start() ==> bundleStartLevel: 30, frameworkStartLevel: 30")); + assertTrue(lines[6].startsWith("Bundle A [1]: start() ==> bundleStartLevel: 40, frameworkStartLevel: 40")); + assertTrue(lines[7].startsWith("Bundle A [1]: stop() ==> bundleStartLevel: 40, frameworkStartLevel: 40")); + assertTrue(lines[8].startsWith("Bundle B [2]: stop() ==> bundleStartLevel: 30, frameworkStartLevel: 30")); + assertTrue(lines[9].startsWith("Bundle C [3]: stop() ==> bundleStartLevel: 20, frameworkStartLevel: 20")); + assertTrue(lines[10].startsWith("Bundle M [4]: stop() ==> bundleStartLevel: 10, frameworkStartLevel: 10")); } // helper methods + PrintStream oldSystemOut = null; + PrintStream oldSystemErr = null; + ByteArrayOutputStream redirectedSystemOut = null; + private void redirectSystemOut() { + // Create a stream to hold the output + redirectedSystemOut = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(redirectedSystemOut); + oldSystemOut = System.out; + oldSystemErr = System.err; + System.setOut(ps); + System.setErr(ps); + } + + private void restoreSystemOut() { + System.setErr(oldSystemErr); + System.setOut(oldSystemOut); + } + + private String getSystemOut() { + String s = redirectedSystemOut.toString(); + return s; + } + + private String[] getSystemOutAsArray() { + String s = redirectedSystemOut.toString(); + String[] lines = s.split("\\R"); + return lines; + } + private File createTmpDir(String prefix) throws IOException { File tmpDir = File.createTempFile(prefix, ".dir"); // System.out.println("tmpDir=" + tmpDir); @@ -239,8 +316,6 @@ private void manipulateStartLevel(BundleContext context, String bsn, int newStar FrameworkStartLevel frameworkStartLevel = framework.adapt(FrameworkStartLevel.class); System.out.print("frameworkStartLevel: " + frameworkStartLevel.getStartLevel() + ", "); - System.out.print("initialBundleStartLevel: " - + frameworkStartLevel.getInitialBundleStartLevel() + ", "); System.out.println(); } } @@ -284,8 +359,6 @@ private void dumpState(BundleContext context, String method) { FrameworkStartLevel frameworkStartLevel = framework.adapt(FrameworkStartLevel.class); System.out.print("frameworkStartLevel: " + frameworkStartLevel.getStartLevel() + ", "); - System.out.print("initialBundleStartLevel: " - + frameworkStartLevel.getInitialBundleStartLevel() + ", "); System.out.println(); } } From 3351af31b8999bbdb7aa0fdea0ee3da4c4013d85 Mon Sep 17 00:00:00 2001 From: Jochen Hiller Date: Fri, 16 Dec 2022 16:03:34 +0100 Subject: [PATCH 4/6] Fixed use case when bundle start level will be set within an bundle activator --- .../org/apache/felix/framework/Felix.java | 33 +++++++++++++++++++ .../framework/FrameworkStartLevelImpl.java | 22 +++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java index 99cbca7664..03858cd2ed 100644 --- a/framework/src/main/java/org/apache/felix/framework/Felix.java +++ b/framework/src/main/java/org/apache/felix/framework/Felix.java @@ -1760,6 +1760,39 @@ void setBundleStartLevel(Bundle bundle, int startLevel) // the start level impl because the spec requires it to be // done synchronously. + // We need to check if the bundle start level set here + // is already in list of start level tuples. + // if so we have to update the start level tuples and re-sort + // the new start level tuple in right start order + // TODO what does happen when new start level is less than + // current framework start level? + synchronized (m_startLevelBundles) { + debug("setBundleStartLevel: check to sync m_startLevelBundles: bundle" + bundle + + ", new level: " + startLevel); + StartLevelTuple foundTuple = null; + for (StartLevelTuple tuple : m_startLevelBundles) { + if (tuple.m_bundle == bundle) { + debug("setBundleStartLevel: found bundle to sync: " + bundle + ", old: " + + tuple.m_level + ", new: " + startLevel); + if (tuple.m_level != startLevel) { + debug("setBundleStartLevel: found bundle to sync: start levels are different " + bundle + ", old: " + + tuple.m_level + ", new: " + startLevel); + foundTuple = tuple; + } + } + } + if (foundTuple != null) { + // update means: remove and add entry to get it in right sort order + debug("setBundleStartLevel: m_startLevelBundles.remove: " + foundTuple); + m_startLevelBundles.remove(foundTuple); + StartLevelTuple updatedTuple = new StartLevelTuple(foundTuple.m_bundle, startLevel); + m_startLevelBundles.add(new StartLevelTuple(foundTuple.m_bundle, startLevel)); + debug("setBundleStartLevel: m_startLevelBundles.added: " + updatedTuple); + } + debugStartLevelBundles("setBundleStartLevel: synced m_startLevelBundles"); + } + + try { // Start the bundle if necessary. diff --git a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java index cfef2b92fb..d40036941e 100644 --- a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java +++ b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java @@ -247,9 +247,25 @@ else if (startlevel <= 0) startThread(); // Synchronously persists the start level. m_bundle.setStartLevel(startlevel); - // Queue request. - m_requests.add(new StartLevelRequest(m_bundle, startlevel)); - m_requests.notifyAll(); + + // if the bundle start level will be changed from FrameworkStartLevel thread, + // we need to process this synchronously, as current thread is busy in a + // bundle activator processing at the moment + if (Thread.currentThread().getName().equals(FrameworkStartLevelImpl.THREAD_NAME)) { + // process Synchronously + debug("BundleStartLevelImpl.setStartLevel: synchronous processing setBundleStartLevel: " + + m_bundle.getBundle() + ", level: " + startlevel); + m_felix.setBundleStartLevel(m_bundle.getBundle(), startlevel); + } else { + // Queue request. + // m_requests.add(new StartLevelRequest(m_bundle, startlevel)); + StartLevelRequest request = new StartLevelRequest(m_bundle, startlevel); + m_requests.add(request); + debug("BundleStartLevelImpl.setStartLevel: m_requests.added: request: " + request); + + debug("BundleStartLevelImpl.setStartLevel: m_requests.notifyAll"); + m_requests.notifyAll(); + } } } From f3c6f30e0a9449626dcad605caac1ae4e41aff3f Mon Sep 17 00:00:00 2001 From: Jochen Hiller Date: Mon, 19 Dec 2022 19:37:05 +0100 Subject: [PATCH 5/6] Change BundleException to replace by an INFO log message in case bundle start level < framework start level --- .../org/apache/felix/framework/Felix.java | 52 +++++-------------- .../framework/FrameworkStartLevelImpl.java | 29 ++++------- .../FrameworkStartLevelImplTest.java | 21 +++++--- 3 files changed, 39 insertions(+), 63 deletions(-) diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java index 03858cd2ed..d4f6a774a8 100644 --- a/framework/src/main/java/org/apache/felix/framework/Felix.java +++ b/framework/src/main/java/org/apache/felix/framework/Felix.java @@ -1760,39 +1760,6 @@ void setBundleStartLevel(Bundle bundle, int startLevel) // the start level impl because the spec requires it to be // done synchronously. - // We need to check if the bundle start level set here - // is already in list of start level tuples. - // if so we have to update the start level tuples and re-sort - // the new start level tuple in right start order - // TODO what does happen when new start level is less than - // current framework start level? - synchronized (m_startLevelBundles) { - debug("setBundleStartLevel: check to sync m_startLevelBundles: bundle" + bundle - + ", new level: " + startLevel); - StartLevelTuple foundTuple = null; - for (StartLevelTuple tuple : m_startLevelBundles) { - if (tuple.m_bundle == bundle) { - debug("setBundleStartLevel: found bundle to sync: " + bundle + ", old: " - + tuple.m_level + ", new: " + startLevel); - if (tuple.m_level != startLevel) { - debug("setBundleStartLevel: found bundle to sync: start levels are different " + bundle + ", old: " - + tuple.m_level + ", new: " + startLevel); - foundTuple = tuple; - } - } - } - if (foundTuple != null) { - // update means: remove and add entry to get it in right sort order - debug("setBundleStartLevel: m_startLevelBundles.remove: " + foundTuple); - m_startLevelBundles.remove(foundTuple); - StartLevelTuple updatedTuple = new StartLevelTuple(foundTuple.m_bundle, startLevel); - m_startLevelBundles.add(new StartLevelTuple(foundTuple.m_bundle, startLevel)); - debug("setBundleStartLevel: m_startLevelBundles.added: " + updatedTuple); - } - debugStartLevelBundles("setBundleStartLevel: synced m_startLevelBundles"); - } - - try { // Start the bundle if necessary. @@ -2256,12 +2223,19 @@ void startBundle(BundleImpl bundle, int options) throws BundleException int bundleLevel = bundle.getStartLevel(getInitialBundleStartLevel()); if (isTransient && (bundleLevel > m_activeStartLevel)) { - // Throw an exception for transient starts. - throw new BundleException( - "Cannot start bundle " + bundle + " because its start level is " - + bundleLevel - + ", which is greater than the framework's start level of " - + m_activeStartLevel + ".", BundleException.START_TRANSIENT_ERROR); + // This can happen if a bundle's start level has been changed when framework is + // starting to framework start level. + // When framework start level has been reached, the start order will be recalculated + // and meanwhile changed start order will be updated. + // This is NOT an ERROR, we simply log an INFO messages as maybe the way start levels + // will be changed needs to be verified + m_logger.log( + Logger.LOG_INFO, + "Will not start bundle " + bundle + " because its start level is " + + bundleLevel + + ", which is greater than the framework's start level of " + + m_activeStartLevel + "."); + return; } else if (bundleLevel > m_targetStartLevel) { diff --git a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java index d40036941e..696246725c 100644 --- a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java +++ b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java @@ -248,24 +248,17 @@ else if (startlevel <= 0) // Synchronously persists the start level. m_bundle.setStartLevel(startlevel); - // if the bundle start level will be changed from FrameworkStartLevel thread, - // we need to process this synchronously, as current thread is busy in a - // bundle activator processing at the moment - if (Thread.currentThread().getName().equals(FrameworkStartLevelImpl.THREAD_NAME)) { - // process Synchronously - debug("BundleStartLevelImpl.setStartLevel: synchronous processing setBundleStartLevel: " - + m_bundle.getBundle() + ", level: " + startlevel); - m_felix.setBundleStartLevel(m_bundle.getBundle(), startlevel); - } else { - // Queue request. - // m_requests.add(new StartLevelRequest(m_bundle, startlevel)); - StartLevelRequest request = new StartLevelRequest(m_bundle, startlevel); - m_requests.add(request); - debug("BundleStartLevelImpl.setStartLevel: m_requests.added: request: " + request); - - debug("BundleStartLevelImpl.setStartLevel: m_requests.notifyAll"); - m_requests.notifyAll(); - } + // Queue request. + // m_requests.add(new StartLevelRequest(m_bundle, startlevel)); + // m_requests.notifyAll(); + + // Queue request. + StartLevelRequest request = new StartLevelRequest(m_bundle, startlevel); + m_requests.add(request); + debug("BundleStartLevelImpl.setStartLevel: m_requests.added: request: " + request); + + debug("BundleStartLevelImpl.setStartLevel: m_requests.notifyAll"); + m_requests.notifyAll(); } } diff --git a/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java index f10211b8c3..bef5a95fca 100644 --- a/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java +++ b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java @@ -62,7 +62,7 @@ public class FrameworkStartLevelImplTest extends TestCase { * start * levels in order of C, B, A. */ - public void testStartLevelStraight() throws Exception { + public void _testStartLevelStraight() throws Exception { redirectSystemOut(); File tmpDir = createTmpDir("generated-bundles"); @@ -116,15 +116,17 @@ public void testStartLevelStraight() throws Exception { /** * This test will install 4 bundles A, B, C, M. Bundles A, B, C will have an - * initial start level of 11. - * Bundle M (start level 10) manipulates start levels in activator for Bundles - * A, B, C that - * start order should be C, B, A. + * initial start level of 15, M of 10. + * The framework will be started to start level 12, Bundle M starts and manipulates + * start levels in activator for Bundles A, B, C that start order should be C, B, A. + * When start level 12 has been reached, the framework will re-calculate now the start order. + * When going to start level 100, bundle will be started in correct order C, B, A. */ + public void testStartLevelManipulatedByBundle() throws Exception { redirectSystemOut(); - int initialBundleStartLevel = 12; // 12, 25, 37 does fail, >40 does work + int initialBundleStartLevel = 15; File tmpDir = createTmpDir("generated-bundles"); File cacheDir = createTmpDir("felix-cache"); @@ -159,6 +161,13 @@ public void testStartLevelManipulatedByBundle() throws Exception { bundleMStartLevel.setStartLevel(10); bundleM.start(); + // if we go to startlevel 12, no bundle needs to be started + // but bundle A-C which have been manipulated are re-calculated when start level 12 + // has been reached + frameworkStartLevel.setStartLevel(12); + Thread.sleep(100); // give chance to startup + + // now go to final start level, bundles C, B, A will be started frameworkStartLevel.setStartLevel(100); Thread.sleep(100); // give chance to startup From a59ec9a32a920a78f525f97f714547a9f87c8785 Mon Sep 17 00:00:00 2001 From: Jochen Hiller Date: Mon, 19 Dec 2022 19:47:41 +0100 Subject: [PATCH 6/6] Removed all debug logging --- .../org/apache/felix/framework/Felix.java | 32 ---------------- .../framework/FrameworkStartLevelImpl.java | 37 +------------------ .../FrameworkStartLevelImplTest.java | 6 +-- 3 files changed, 5 insertions(+), 70 deletions(-) diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java index d4f6a774a8..62643fb9e3 100644 --- a/framework/src/main/java/org/apache/felix/framework/Felix.java +++ b/framework/src/main/java/org/apache/felix/framework/Felix.java @@ -110,18 +110,6 @@ public class Felix extends BundleImpl implements Framework { - // poor mans debugging - static final boolean SHOW_DEBUG = true; - static void debug(String msg) { - debug("[Felix]", msg); - } - static void debug(String className, String msg) { - if (! SHOW_DEBUG) return; - String thread = Thread.currentThread().toString().substring(6); - String logMsg = String.format("%-25s %-25s %s", thread, className, msg); - System.out.println(logMsg); - } - // The secure action used to do privileged calls static final SecureAction m_secureAction = new SecureAction(); @@ -192,13 +180,6 @@ static void debug(String className, String msg) { private final SortedSet m_startLevelBundles = new TreeSet(); - private void debugStartLevelBundles(String msg) { - debug("dumpStartLevelBundles: " + msg); - for (StartLevelTuple t : m_startLevelBundles) { - debug(" tuple: " + t); - } - } - // Local bundle cache. private BundleCache m_cache = null; @@ -1485,7 +1466,6 @@ void setActiveStartLevel(int requestedLevel, FrameworkListener[] listeners) (BundleImpl) b, ((BundleImpl) b).getStartLevel( getInitialBundleStartLevel()))); - debugStartLevelBundles("setActiveStartLevel: m_startLevelBundles.added bundle " + b.toString()); } bundlesRemaining = !m_startLevelBundles.isEmpty(); } @@ -1530,9 +1510,6 @@ void setActiveStartLevel(int requestedLevel, FrameworkListener[] listeners) } } - debug("setActiveStartLevel: process next tuple: " + tuple - + ", m_activeStartLevel: " + m_activeStartLevel); - // Ignore the system bundle, since its start() and // stop() methods get called explicitly in Felix.start() // and Felix.stop(), respectively. @@ -1560,7 +1537,6 @@ void setActiveStartLevel(int requestedLevel, FrameworkListener[] listeners) synchronized (m_startLevelBundles) { m_startLevelBundles.remove(tuple); - debugStartLevelBundles("setActiveStartLevel: m_startLevelBundles.removed " + tuple.toString()); bundlesRemaining = !m_startLevelBundles.isEmpty(); } } @@ -1626,7 +1602,6 @@ else if (isLowering synchronized (m_startLevelBundles) { m_startLevelBundles.remove(tuple); - debugStartLevelBundles("setActiveStartLevel: m_startLevelBundles.remove tuple " + tuple.toString()); bundlesRemaining = !m_startLevelBundles.isEmpty(); } } @@ -2249,8 +2224,6 @@ else if (bundleLevel > m_targetStartLevel) // queued but processed synchronously. // Note: Don't queue starts from the start level thread, otherwise // we'd never get anything started. - debug("startBundle: bundle: " + bundle.getSymbolicName() + ", level: " + bundleLevel - + ", check thread: " + Thread.currentThread().getName()+ ", fw: " + FrameworkStartLevelImpl.THREAD_NAME); if (!Thread.currentThread().getName().equals(FrameworkStartLevelImpl.THREAD_NAME)) { synchronized (m_startLevelBundles) @@ -2297,7 +2270,6 @@ else if (bundleLevel > m_targetStartLevel) if (!found) { m_startLevelBundles.add(new StartLevelTuple(bundle, bundleLevel)); - debugStartLevelBundles("startBundle: m_startLevelBundles.added bundle " + bundle + ", " + bundleLevel); } // Note that although we queued the transiently started @@ -5430,10 +5402,6 @@ else if (m_bundle.getBundleId() == t.m_bundle.getBundleId()) return result; } - - public String toString() { - return "StartLevelTuple(" + m_bundle + ", " + m_level + ")"; - } } // diff --git a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java index 696246725c..53a8d7e318 100644 --- a/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java +++ b/framework/src/main/java/org/apache/felix/framework/FrameworkStartLevelImpl.java @@ -32,11 +32,6 @@ class FrameworkStartLevelImpl implements FrameworkStartLevel, Runnable { - // poor mans debugging - static void debug(String msg) { - Felix.debug("[FrameworkStartLevelImpl]", msg); - } - static final String THREAD_NAME = "FelixStartLevel"; private final Felix m_felix; @@ -69,7 +64,6 @@ private void startThread() m_thread = new Thread(this, THREAD_NAME); m_thread.setDaemon(true); m_thread.start(); - debug("startThread: thread started"); } } @@ -94,7 +88,6 @@ void stop() // Wake up the thread, if it is currently in the wait() state // for more work. - debug ("stop: m_requests.notifyAll"); m_requests.notifyAll(); } } @@ -133,12 +126,7 @@ public void setStartLevel(int startlevel, FrameworkListener... listeners) throw new IllegalStateException("No inital startlevel yet"); } // Queue request. - // m_requests.add(new StartLevelRequest(null, startlevel, listeners)); - StartLevelRequest request = new StartLevelRequest(null, startlevel, listeners); - m_requests.add(request); - debug("setStartLevel: m_requests.added request: " + request); - - debug ("setStartLevel: m_requests.notifyAll"); + m_requests.add(new StartLevelRequest(null, startlevel, listeners)); m_requests.notifyAll(); } } @@ -160,13 +148,11 @@ public void setStartLevel(int startlevel, FrameworkListener... listeners) startThread(); // Queue request. m_requests.add(request); - debug("setStartLevelAndWait: m_requests.added: request: " + request); m_requests.notifyAll(); } try { - debug("setStartLevelAndWait: request.wait"); request.wait(); } catch (InterruptedException ex) @@ -247,17 +233,8 @@ else if (startlevel <= 0) startThread(); // Synchronously persists the start level. m_bundle.setStartLevel(startlevel); - - // Queue request. - // m_requests.add(new StartLevelRequest(m_bundle, startlevel)); - // m_requests.notifyAll(); - // Queue request. - StartLevelRequest request = new StartLevelRequest(m_bundle, startlevel); - m_requests.add(request); - debug("BundleStartLevelImpl.setStartLevel: m_requests.added: request: " + request); - - debug("BundleStartLevelImpl.setStartLevel: m_requests.notifyAll"); + m_requests.add(new StartLevelRequest(m_bundle, startlevel)); m_requests.notifyAll(); } } @@ -284,19 +261,16 @@ public void run() synchronized (m_requests) { // Wait for a request. - debug("run: m_requests.size: " + m_requests.size()); while (m_requests.isEmpty()) { // Terminate the thread if requested to do so (see stop()). if (m_thread == null) { - debug("run: thread stopped"); return; } try { - debug("run: m_requests.wait"); m_requests.wait(); } catch (InterruptedException ex) @@ -307,7 +281,6 @@ public void run() // Get the requested start level. request = m_requests.remove(0); - debug("run: m_requests.remove request: " + request); } // If the request object has no bundle, then the request @@ -337,7 +310,6 @@ public void run() synchronized (m_requests) { m_requests.add(0, request); - debug("run: m_requests.added request: " + request); previousRequest = request; } } @@ -356,7 +328,6 @@ public void run() // Notify any waiting thread that this request is done. synchronized (request) { - debug("run: request.notifyAll"); request.notifyAll(); } } @@ -393,9 +364,5 @@ public FrameworkListener[] getListeners() { return m_listeners; } - - public String toString() { - return "StartLevelRequest(" + m_bundle + ", " + m_startLevel + ")"; - } } } diff --git a/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java index bef5a95fca..cab463ff19 100644 --- a/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java +++ b/framework/src/test/java/org/apache/felix/framework/FrameworkStartLevelImplTest.java @@ -62,7 +62,7 @@ public class FrameworkStartLevelImplTest extends TestCase { * start * levels in order of C, B, A. */ - public void _testStartLevelStraight() throws Exception { + public void testStartLevelStraight() throws Exception { redirectSystemOut(); File tmpDir = createTmpDir("generated-bundles"); @@ -102,7 +102,7 @@ public void _testStartLevelStraight() throws Exception { restoreSystemOut(); - System.out.println(getSystemOut()); // enable on demand + // System.out.println(getSystemOut()); // enable on demand String[] lines = getSystemOutAsArray(); @@ -178,7 +178,7 @@ public void testStartLevelManipulatedByBundle() throws Exception { restoreSystemOut(); - System.out.println(getSystemOut()); // enable on demand + // System.out.println(getSystemOut()); // enable on demand String[] lines = getSystemOutAsArray(); assertTrue(lines[0].startsWith("Bundle M [4]: start() ==> bundleStartLevel: 10"));