diff options
17 files changed, 1336 insertions, 761 deletions
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleInstaller.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleInstaller.java index c9caed10a..2b63d611f 100644 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleInstaller.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleInstaller.java @@ -49,6 +49,14 @@ public class BundleInstaller { synchronized public Bundle installBundle(String name, boolean track) throws BundleException { if (bundles == null && track) return null; + String location = getBundleLocation(name); + Bundle bundle = context.installBundle(location); + if (track) + bundles.put(name, bundle); + return bundle; + } + + public String getBundleLocation(String name) throws BundleException { String bundleFileName = rootLocation + "/" + name; URL bundleURL = context.getBundle().getEntry(bundleFileName); if (bundleURL == null) @@ -63,10 +71,7 @@ public class BundleInstaller { String location = bundleURL.toExternalForm(); if ("file".equals(bundleURL.getProtocol())) location = "reference:" + location; - Bundle bundle = context.installBundle(location); - if (track) - bundles.put(name, bundle); - return bundle; + return location; } synchronized public Bundle updateBundle(String fromName, String toName) throws BundleException { diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleTests.java index 06567d1aa..8f4e75d11 100644 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleTests.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/BundleTests.java @@ -16,6 +16,7 @@ import junit.framework.TestSuite; public class BundleTests { public static Test suite() { TestSuite suite = new TestSuite(BundleTests.class.getName()); + suite.addTest(SystemBundleTests.suite()); suite.addTest(ServiceRegistryBundleTests.suite()); suite.addTest(SubstituteExportsBundleTests.suite()); suite.addTest(PackageAdminBundleTests.suite()); diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java new file mode 100644 index 000000000..4184c5540 --- /dev/null +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java @@ -0,0 +1,496 @@ +/******************************************************************************* + * Copyright (c) 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgi.tests.bundles; + +import java.io.File; +import java.net.URL; +import java.util.Properties; +import junit.framework.Test; +import junit.framework.TestSuite; +import org.eclipse.osgi.launch.Equinox; +import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.osgi.tests.OSGiTestsActivator; +import org.osgi.framework.*; +import org.osgi.framework.launch.SystemBundle; + +public class SystemBundleTests extends AbstractBundleTests { + public static Test suite() { + return new TestSuite(SystemBundleTests.class); + } + + public void testSystemBundle01() { + // simple test to create an embedded framework + File config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle01"); //$NON-NLS-1$ + Properties configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + Equinox equinox = new Equinox(); + equinox.init(configuration); + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + BundleContext systemContext = equinox.getBundleContext(); + assertNotNull("SystemBundle context is null", systemContext); //$NON-NLS-1$ + + ServiceReference[] refs = null; + try { + refs = systemContext.getServiceReferences(Location.class.getName(), "(type=osgi.configuration.area)"); //$NON-NLS-1$ + } catch (InvalidSyntaxException e) { + fail("Unexpected syntax error", e); //$NON-NLS-1$ + } + assertNotNull("Configuration Location refs is null", refs); //$NON-NLS-1$ + assertEquals("config refs length is wrong", 1, refs.length); //$NON-NLS-1$ + Location configLocation = (Location) systemContext.getService(refs[0]); + URL configURL = configLocation.getURL(); + assertTrue("incorrect configuration location", configURL.toExternalForm().endsWith("testSystemBundle01/")); //$NON-NLS-1$ //$NON-NLS-2$ + + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + } + + public void testSystemBundle02() { + // create/start/stop/start/stop test + File config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle02"); //$NON-NLS-1$ + Properties configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + Equinox equinox = new Equinox(); + equinox.init(configuration); + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + } + + public void testSystemBundle03() { + // create/stop/ test + File config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle03"); //$NON-NLS-1$ + Properties configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + Equinox equinox = new Equinox(); + equinox.init(configuration); + // should be in the STARTING state + assertEquals("Wrong state for SystemBundle", Bundle.STARTING, equinox.getState()); //$NON-NLS-1$ + BundleContext systemContext = equinox.getBundleContext(); + assertNotNull("System context is null", systemContext); //$NON-NLS-1$ + String configArea = systemContext.getProperty("osgi.configuration.area"); //$NON-NLS-1$ + assertNotNull("config property is null", configArea); //$NON-NLS-1$ + assertTrue("Wrong configuration area", configArea.endsWith("testSystemBundle03/")); //$NON-NLS-1$ //$NON-NLS-2$ + // don't do anything; just put the framework back to the RESOLVED state + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected error stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + } + + public void testSystemBundle04() { + // create/start/stop/start/stop test + File config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle04"); //$NON-NLS-1$ + Properties configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + Equinox equinox = new Equinox(); + equinox.init(configuration); + // should be in the STARTING state + assertEquals("Wrong state for SystemBundle", Bundle.STARTING, equinox.getState()); //$NON-NLS-1$ + BundleContext systemContext = equinox.getBundleContext(); + assertNotNull("System context is null", systemContext); //$NON-NLS-1$ + // try installing a bundle before starting + Bundle substitutesA = null; + try { + substitutesA = systemContext.installBundle(installer.getBundleLocation("substitutes.a")); //$NON-NLS-1$ + } catch (BundleException e1) { + fail("failed to install a bundle", e1); //$NON-NLS-1$ + } + try { + substitutesA.start(); + } catch (BundleException e) { + fail("Unexpected bundle exception", e); //$NON-NLS-1$ + } + + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + assertEquals("Wrong state for installed bundle", Bundle.ACTIVE, substitutesA.getState()); //$NON-NLS-1$ + // put the framework back to the RESOLVED state + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + } + + public void testSystemBundle05_1() { + // create/install/start/stop test + File config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle05_1"); //$NON-NLS-1$ + Properties configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + Equinox equinox = new Equinox(); + equinox.init(configuration); + // should be in the STARTING state + assertEquals("Wrong state for SystemBundle", Bundle.STARTING, equinox.getState()); //$NON-NLS-1$ + BundleContext systemContext = equinox.getBundleContext(); + assertNotNull("System context is null", systemContext); //$NON-NLS-1$ + // try installing a bundle before starting + Bundle substitutesA = null; + try { + substitutesA = systemContext.installBundle(installer.getBundleLocation("substitutes.a")); //$NON-NLS-1$ + } catch (BundleException e1) { + fail("failed to install a bundle", e1); //$NON-NLS-1$ + } + // start framework first + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + assertEquals("Wrong state for installed bundle", Bundle.INSTALLED, substitutesA.getState()); //$NON-NLS-1$ + try { + substitutesA.start(); + } catch (BundleException e1) { + fail("Failed to start a bundle", e1); //$NON-NLS-1$ + } + assertEquals("Wrong state for active bundle", Bundle.ACTIVE, substitutesA.getState()); //$NON-NLS-1$ + // put the framework back to the RESOLVED state + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + } + + public void testSystemBundle05_2() { + // create/install/start/stop/start/stop test + File config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle05_2"); //$NON-NLS-1$ + Properties configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + Equinox equinox = new Equinox(); + equinox.init(configuration); + // should be in the STARTING state + assertEquals("Wrong state for SystemBundle", Bundle.STARTING, equinox.getState()); //$NON-NLS-1$ + BundleContext systemContext = equinox.getBundleContext(); + assertNotNull("System context is null", systemContext); //$NON-NLS-1$ + // try installing a bundle before starting + Bundle substitutesA = null; + try { + substitutesA = systemContext.installBundle(installer.getBundleLocation("substitutes.a")); //$NON-NLS-1$ + } catch (BundleException e1) { + fail("failed to install a bundle", e1); //$NON-NLS-1$ + } + // start framework first + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + assertEquals("Wrong state for installed bundle", Bundle.INSTALLED, substitutesA.getState()); //$NON-NLS-1$ + try { + substitutesA.start(); + } catch (BundleException e1) { + fail("Failed to start a bundle", e1); //$NON-NLS-1$ + } + assertEquals("Wrong state for active bundle", Bundle.ACTIVE, substitutesA.getState()); //$NON-NLS-1$ + // put the framework back to the RESOLVED state + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + Bundle substitutesA2 = null; + try { + substitutesA2 = equinox.getBundleContext().installBundle(installer.getBundleLocation("substitutes.a")); //$NON-NLS-1$ + } catch (BundleException e) { + fail("Unexpected exception installing", e); //$NON-NLS-1$ + } + // assert the same bundle ID + assertEquals("Bundle ids are not the same", substitutesA.getBundleId(), substitutesA2.getBundleId()); //$NON-NLS-1$ + // no need to start the bundle again it should have been persistently started + assertEquals("Wrong state for active bundle", Bundle.ACTIVE, substitutesA2.getState()); //$NON-NLS-1$ + // put the framework back to the RESOLVED state + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + + } + + public void testSystemBundle06() { + // create multiple instances test + File config1 = OSGiTestsActivator.getContext().getDataFile("testSystemBundle06_1"); //$NON-NLS-1$ + Properties configuration1 = new Properties(); + configuration1.put(SystemBundle.STORAGE, config1.getAbsolutePath()); + Equinox equinox1 = new Equinox(); + equinox1.init(configuration1); + // should be in the STARTING state + assertEquals("Wrong state for SystemBundle", Bundle.STARTING, equinox1.getState()); //$NON-NLS-1$ + + File config2 = OSGiTestsActivator.getContext().getDataFile("testSystemBundle06_2"); //$NON-NLS-1$ + Properties configuration2 = new Properties(); + configuration2.put(SystemBundle.STORAGE, config2.getAbsolutePath()); + Equinox equinox2 = new Equinox(); + equinox2.init(configuration2); + // should be in the STARTING state + assertEquals("Wrong state for SystemBundle", Bundle.STARTING, equinox2.getState()); //$NON-NLS-1$ + + BundleContext systemContext1 = equinox1.getBundleContext(); + assertNotNull("System context is null", systemContext1); //$NON-NLS-1$ + BundleContext systemContext2 = equinox2.getBundleContext(); + assertNotNull("System context is null", systemContext2); //$NON-NLS-1$ + + assertNotSame(systemContext1, systemContext2); + + // start framework 1 first + try { + equinox1.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox1.getState()); //$NON-NLS-1$ + // start framework 2 first + try { + equinox2.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox2.getState()); //$NON-NLS-1$ + + // put the framework 1 back to the RESOLVED state + try { + equinox1.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox1.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox1.getState()); //$NON-NLS-1$ + + // put the framework 1 back to the RESOLVED state + try { + equinox2.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox2.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox2.getState()); //$NON-NLS-1$ + } + + public void testSystemBundle07() { + // test init twice + File config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle07_01"); //$NON-NLS-1$ + Properties configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + Equinox equinox = new Equinox(); + equinox.init(configuration); + + config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle07_02"); //$NON-NLS-1$ + configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + try { + equinox.init(configuration); + fail("Failed to throw illegal state exception on double init"); //$NON-NLS-1$ + } catch (IllegalStateException e) { + // expected + } + + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + BundleContext systemContext = equinox.getBundleContext(); + assertNotNull("SystemBundle context is null", systemContext); //$NON-NLS-1$ + + try { + equinox.init(configuration); + fail("Failed to throw illegal state exception on double init"); //$NON-NLS-1$ + } catch (IllegalStateException e) { + // expected + } + + ServiceReference[] refs = null; + try { + refs = systemContext.getServiceReferences(Location.class.getName(), "(type=osgi.configuration.area)"); //$NON-NLS-1$ + } catch (InvalidSyntaxException e) { + fail("Unexpected syntax error", e); //$NON-NLS-1$ + } + assertNotNull("Configuration Location refs is null", refs); //$NON-NLS-1$ + assertEquals("config refs length is wrong", 1, refs.length); //$NON-NLS-1$ + Location configLocation = (Location) systemContext.getService(refs[0]); + URL configURL = configLocation.getURL(); + assertTrue("incorrect configuration location", configURL.toExternalForm().endsWith("testSystemBundle07_01/")); //$NON-NLS-1$ //$NON-NLS-2$ + + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + } + + public void testSystemBundle08() { + // create/start/stop/start/stop test + File config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle08_1"); //$NON-NLS-1$ + Properties configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + Equinox equinox = new Equinox(); + equinox.init(configuration); + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + + config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle08_2"); //$NON-NLS-1$ + configuration = new Properties(); + configuration.put(SystemBundle.STORAGE, config.getAbsolutePath()); + equinox.init(configuration); + + try { + equinox.start(); + } catch (BundleException e) { + fail("Failed to start the framework", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$ + + ServiceReference[] refs = null; + try { + refs = equinox.getBundleContext().getServiceReferences(Location.class.getName(), "(type=osgi.configuration.area)"); //$NON-NLS-1$ + } catch (InvalidSyntaxException e) { + fail("Unexpected syntax error", e); //$NON-NLS-1$ + } + assertNotNull("Configuration Location refs is null", refs); //$NON-NLS-1$ + assertEquals("config refs length is wrong", 1, refs.length); //$NON-NLS-1$ + Location configLocation = (Location) equinox.getBundleContext().getService(refs[0]); + URL configURL = configLocation.getURL(); + assertTrue("incorrect configuration location", configURL.toExternalForm().endsWith("testSystemBundle08_2/")); //$NON-NLS-1$ //$NON-NLS-2$ + + try { + equinox.stop(); + } catch (BundleException e) { + fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$ + } + try { + equinox.waitForStop(10000); + } catch (InterruptedException e) { + fail("Unexpected interrupted exception", e); //$NON-NLS-1$ + } + assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.osgi/.settings/.api_filters b/bundles/org.eclipse.osgi/.settings/.api_filters index d73bde2fc..b15c9fb02 100644 --- a/bundles/org.eclipse.osgi/.settings/.api_filters +++ b/bundles/org.eclipse.osgi/.settings/.api_filters @@ -1,5 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?>
<component id="org.eclipse.osgi" version="2">
+<resource path="osgi/src/org/osgi/framework/launch/SystemBundle.java" type="org.osgi.framework.launch.SystemBundle">
+<filter id="1110441988">
+<message_arguments>
+<message_argument value="org.osgi.framework.launch.SystemBundle"/>
+</message_arguments>
+</filter>
+</resource>
<resource path="osgi/src/org/osgi/framework/hooks/service/FindHook.java" type="org.osgi.framework.hooks.service.FindHook">
<filter id="1110441988">
<message_arguments>
@@ -50,31 +57,31 @@ </message_arguments>
</filter>
</resource>
-<resource path="osgi/src/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java" type="org.osgi.service.condpermadmin.ConditionalPermissionAdmin">
-<filter id="1209008130">
+<resource path="osgi/src/org/osgi/framework/hooks/service/ListenerHook.java" type="org.osgi.framework.hooks.service.ListenerHook">
+<filter id="1110441988">
<message_arguments>
-<message_argument value="1.1"/>
-<message_argument value="3.4"/>
-<message_argument value="org.osgi.service.condpermadmin.ConditionalPermissionAdmin"/>
+<message_argument value="org.osgi.framework.hooks.service.ListenerHook"/>
</message_arguments>
</filter>
+</resource>
+<resource path="osgi/src/org/osgi/service/condpermadmin/ConditionalPermissionAdmin.java" type="org.osgi.service.condpermadmin.ConditionalPermissionAdmin">
<filter id="403804204">
<message_arguments>
<message_argument value="org.osgi.service.condpermadmin.ConditionalPermissionAdmin"/>
<message_argument value="createConditionalPermissionInfoBase(String, ConditionInfo[], PermissionInfo[], String)"/>
</message_arguments>
</filter>
-<filter id="403804204">
+<filter id="1209008130">
<message_arguments>
+<message_argument value="1.1"/>
+<message_argument value="3.4"/>
<message_argument value="org.osgi.service.condpermadmin.ConditionalPermissionAdmin"/>
-<message_argument value="createConditionalPermissionsUpdate()"/>
</message_arguments>
</filter>
-</resource>
-<resource path="osgi/src/org/osgi/framework/hooks/service/ListenerHook.java" type="org.osgi.framework.hooks.service.ListenerHook">
-<filter id="1110441988">
+<filter id="403804204">
<message_arguments>
-<message_argument value="org.osgi.framework.hooks.service.ListenerHook"/>
+<message_argument value="org.osgi.service.condpermadmin.ConditionalPermissionAdmin"/>
+<message_argument value="createConditionalPermissionsUpdate()"/>
</message_arguments>
</filter>
</resource>
diff --git a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF index daa56c761..42705a5a5 100644 --- a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF @@ -4,6 +4,7 @@ Export-Package: org.eclipse.osgi.event;version="1.0", org.eclipse.osgi.framework.console;version="1.0", org.eclipse.osgi.framework.eventmgr;version="1.1", org.eclipse.osgi.framework.log;version="1.0", + org.eclipse.osgi.launch; version="1.0", org.eclipse.osgi.service.datalocation;version="1.1", org.eclipse.osgi.service.debug;version="1.0", org.eclipse.osgi.service.environment;version="1.1", @@ -17,6 +18,7 @@ Export-Package: org.eclipse.osgi.event;version="1.0", org.eclipse.osgi.storagemanager;version="1.0", org.eclipse.osgi.util;version="1.1", org.osgi.framework;version="1.5", + org.osgi.framework.launch; version="1.0", org.osgi.framework.hooks.service; version="1.0", org.osgi.service.condpermadmin;version="1.1", org.osgi.service.packageadmin;version="1.2", @@ -39,7 +41,6 @@ Export-Package: org.eclipse.osgi.event;version="1.0", org.eclipse.osgi.framework.internal.protocol.bundleresource;x-internal:=true, org.eclipse.osgi.framework.internal.protocol.reference;x-internal:=true, org.eclipse.osgi.framework.internal.reliablefile;x-internal:=true, - org.eclipse.osgi.framework.launcher;x-internal:=true, org.eclipse.osgi.framework.util;x-internal:=true, org.eclipse.osgi.internal.baseadaptor;x-internal:=true, org.eclipse.osgi.internal.module;x-internal:=true, diff --git a/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandProvider.java b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandProvider.java index f2a2e8ad9..237ae4d85 100644 --- a/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandProvider.java +++ b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkCommandProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2003, 2007 IBM Corporation and others. + * Copyright (c) 2003, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -19,7 +19,6 @@ import java.security.ProtectionDomain; import java.util.*; import org.eclipse.osgi.framework.console.CommandInterpreter; import org.eclipse.osgi.framework.console.CommandProvider; -import org.eclipse.osgi.framework.launcher.Launcher; import org.eclipse.osgi.internal.permadmin.SecurityAdmin; import org.eclipse.osgi.internal.profile.Profile; import org.eclipse.osgi.service.resolver.*; @@ -80,7 +79,7 @@ import org.osgi.service.packageadmin.RequiredBundle; public class FrameworkCommandProvider implements CommandProvider, SynchronousBundleListener { /** An instance of the OSGi framework */ - private OSGi osgi; + private Framework framework; /** The system bundle context */ private org.osgi.framework.BundleContext context; /** The start level implementation */ @@ -100,13 +99,13 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun * * initialize must be called after creating this object. * - * @param osgi The current instance of OSGi + * @param framework The current instance of the framework */ - public FrameworkCommandProvider(OSGi osgi) { - this.osgi = osgi; - context = osgi.getBundleContext(); - slImpl = osgi.framework.startLevelManager; - securityAdmin = osgi.framework.securityAdmin; + public FrameworkCommandProvider(Framework framework) { + this.framework = framework; + context = framework.systemBundle.getContext(); + slImpl = framework.startLevelManager; + securityAdmin = framework.securityAdmin; } /** @@ -217,7 +216,7 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun * @param intp A CommandInterpreter object containing the command and it's arguments. */ public void _launch(CommandInterpreter intp) throws Exception { - osgi.launch(); + framework.launch(); } /** @@ -226,7 +225,7 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun * @param intp A CommandInterpreter object containing the command and it's arguments. */ public void _shutdown(CommandInterpreter intp) throws Exception { - osgi.shutdown(); + framework.shutdown(); } /** @@ -312,7 +311,7 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun if (nextArg != null) { String start = nextArg.toLowerCase(); - if (Launcher.matchCommand("start", start, 1)) { //$NON-NLS-1$ + if (matchCommand("start", start, 1)) { //$NON-NLS-1$ bundle.start(); } } @@ -320,6 +319,15 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun } + private static boolean matchCommand(String command, String input, int minLength) { + if (minLength <= 0) + minLength = command.length(); + int length = input.length(); + if (minLength > length) + length = minLength; + return (command.regionMatches(0, input, 0, length)); + } + /** * Handle the update command's abbreviation. Invoke _update() * @@ -455,7 +463,7 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun * @param intp A CommandInterpreter object containing the command and it's arguments. */ public void _status(CommandInterpreter intp) throws Exception { - if (osgi.isActive()) { + if (framework.isActive()) { intp.println(ConsoleMsg.CONSOLE_FRAMEWORK_IS_LAUNCHED_MESSAGE); } else { intp.println(ConsoleMsg.CONSOLE_FRAMEWORK_IS_SHUTDOWN_MESSAGE); @@ -664,7 +672,7 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun intp.print(", "); //$NON-NLS-1$ intp.print(NLS.bind(ConsoleMsg.CONSOLE_STATUS_MESSAGE, getStateName(bundle))); if (id != 0) { - File dataRoot = osgi.framework.getDataFile(bundle, ""); //$NON-NLS-1$ + File dataRoot = framework.getDataFile(bundle, ""); //$NON-NLS-1$ String root = (dataRoot == null) ? null : dataRoot.getAbsolutePath(); @@ -730,7 +738,7 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun intp.print(", "); //$NON-NLS-1$ intp.print(NLS.bind(ConsoleMsg.CONSOLE_STATUS_MESSAGE, getStateName(bundle))); if (id != 0) { - File dataRoot = osgi.framework.getDataFile(bundle, ""); //$NON-NLS-1$ + File dataRoot = framework.getDataFile(bundle, ""); //$NON-NLS-1$ String root = (dataRoot == null) ? null : dataRoot.getAbsolutePath(); @@ -1102,7 +1110,7 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun * @param intp A CommandInterpreter object containing the command and it's arguments. */ public void _init(CommandInterpreter intp) throws Exception { - if (osgi.isActive()) { + if (framework.isActive()) { intp.print(newline); intp.println(ConsoleMsg.CONSOLE_FRAMEWORK_LAUNCHED_PLEASE_SHUTDOWN_MESSAGE); return; @@ -1148,7 +1156,7 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun */ public void _close(CommandInterpreter intp) throws Exception { intp.println(); - osgi.close(); + framework.close(); System.exit(0); } @@ -1344,7 +1352,7 @@ public class FrameworkCommandProvider implements CommandProvider, SynchronousBun * @param intp A CommandInterpreter object containing the command and it's arguments. */ public void _ss(CommandInterpreter intp) throws Exception { - if (osgi.isActive()) { + if (framework.isActive()) { intp.println(); intp.println(ConsoleMsg.CONSOLE_FRAMEWORK_IS_LAUNCHED_MESSAGE); } else { diff --git a/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkConsole.java b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkConsole.java index 86c55125e..102e5b630 100644 --- a/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkConsole.java +++ b/bundles/org.eclipse.osgi/console/src/org/eclipse/osgi/framework/internal/core/FrameworkConsole.java @@ -32,8 +32,6 @@ public class FrameworkConsole implements Runnable { protected PrintWriter out; /** The current bundle context */ protected final org.osgi.framework.BundleContext context; - /** The current osgi instance */ - protected final OSGi osgi; /** The command line arguments passed at launch time*/ protected final String[] args; /** The OSGi Command Provider */ @@ -59,37 +57,36 @@ public class FrameworkConsole implements Runnable { Constructor for FrameworkConsole. It creates a service tracker to track CommandProvider registrations. The console InputStream is set to System.in and the console PrintStream is set to System.out. - @param osgi - an instance of an osgi framework + @param framework - an instance of an osgi framework @param args - any arguments passed on the command line when Launcher is started. */ - public FrameworkConsole(OSGi osgi, String[] args) { - this(osgi, args, 0, false); + public FrameworkConsole(Framework framework, String[] args) { + this(framework, args, 0, false); } /** Constructor for FrameworkConsole. It creates a service tracker to track CommandProvider registrations. The console InputStream is set to System.in and the console PrintStream is set to System.out. - @param osgi - an instance of an osgi framework + @param framework - an instance of an osgi framework @param args - any arguments passed on the command line when Launcher is started. */ - public FrameworkConsole(OSGi osgi, int port, String[] args) { - this(osgi, args, port, true); + public FrameworkConsole(Framework framework, int port, String[] args) { + this(framework, args, port, true); } - private FrameworkConsole(OSGi osgi, String[] args, int port, boolean useSocketStream) { + private FrameworkConsole(Framework framework, String[] args, int port, boolean useSocketStream) { this.args = args; - this.osgi = osgi; this.useSocketStream = useSocketStream; this.port = port; - this.context = osgi.getBundleContext(); + this.context = framework.systemBundle.getContext(); // set up a service tracker to track CommandProvider registrations this.cptracker = new ServiceTracker(context, CommandProvider.class.getName(), null); this.cptracker.open(); // register the OSGi command provider - this.osgicp = new FrameworkCommandProvider(osgi).intialize(); + this.osgicp = new FrameworkCommandProvider(framework).intialize(); } /** diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/EquinoxSystemBundle.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/EquinoxSystemBundle.java new file mode 100644 index 000000000..5ae3ce266 --- /dev/null +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/EquinoxSystemBundle.java @@ -0,0 +1,260 @@ +/******************************************************************************* + * Copyright (c) 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgi.framework.internal.core; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.*; +import org.eclipse.core.runtime.adaptor.EclipseStarter; +import org.eclipse.core.runtime.adaptor.LocationManager; +import org.eclipse.osgi.baseadaptor.BaseAdaptor; +import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; +import org.osgi.framework.*; +import org.osgi.framework.launch.SystemBundle; + +public class EquinoxSystemBundle implements SystemBundle { + + private static String FULLPATH = " [fullpath]"; //$NON-NLS-1$ + private volatile Framework framework; + private volatile Bundle systemBundle; + + public void init(Properties configuration) { + internalInit(configuration); + } + + private Framework internalInit(Properties configuration) { + Framework current = framework; + if (current != null) { + // this is not really necessary because the Equinox class will + current.close(); + framework = null; + systemBundle = null; + } + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + try { + FrameworkProperties.setProperties(configuration); + FrameworkProperties.initializeProperties(); + // make sure the active framework thread is used + setEquinoxProperties(configuration); + current = new Framework(new BaseAdaptor(new String[0])); + current.launch(); + framework = current; + systemBundle = current.systemBundle; + } finally { + ClassLoader currentCCL = Thread.currentThread().getContextClassLoader(); + if (currentCCL != tccl) + Thread.currentThread().setContextClassLoader(tccl); + } + return current; + } + + private void setEquinoxProperties(Properties configuration) { + // always need to use an active thread + FrameworkProperties.setProperty(Framework.PROP_FRAMEWORK_THREAD, Framework.THREAD_NORMAL); + + // first check props we are required to provide reasonable defaults for + String windowSystem = configuration == null ? null : configuration.getProperty(SystemBundle.WINDOWSYSTEM); + if (windowSystem == null) { + windowSystem = FrameworkProperties.getProperty(EclipseStarter.PROP_WS); + if (windowSystem != null) + FrameworkProperties.setProperty(SystemBundle.WINDOWSYSTEM, windowSystem); + } + // rest of props can be ignored if the configuration is null + if (configuration == null) + return; + // check each osgi defined property and set the appropriate equinox one + String security = configuration.getProperty(SystemBundle.SECURITY); + if (security != null) { + if (Boolean.valueOf(security).booleanValue()) + FrameworkProperties.setProperty(Framework.PROP_EQUINOX_SECURITY, Framework.SECURITY_OSGI); + else + FrameworkProperties.setProperty(Framework.PROP_EQUINOX_SECURITY, security); + } + String storage = configuration.getProperty(SystemBundle.STORAGE); + if (storage != null) { + FrameworkProperties.setProperty(LocationManager.PROP_CONFIG_AREA, storage); + FrameworkProperties.setProperty(LocationManager.PROP_CONFIG_AREA_DEFAULT, storage); + } + String execPermission = configuration.getProperty(SystemBundle.EXECPERMISSION); + if (execPermission != null) { + if (!execPermission.endsWith(FULLPATH)) + execPermission = execPermission + FULLPATH; + FrameworkProperties.setProperty("osgi.filepermissions.command", execPermission); //$NON-NLS-1$ + } + + } + + public void waitForStop(long timeout) throws InterruptedException { + Framework current = framework; + if (current == null) + return; + current.waitForStop(timeout); + } + + public Enumeration findEntries(String path, String filePattern, boolean recurse) { + Bundle current = systemBundle; + if (current == null) + return null; + return current.findEntries(path, filePattern, recurse); + } + + public BundleContext getBundleContext() { + Bundle current = systemBundle; + if (current == null) + return null; + return current.getBundleContext(); + } + + public long getBundleId() { + return 0; + } + + public URL getEntry(String path) { + Bundle current = systemBundle; + if (current == null) + return null; + return current.getEntry(path); + } + + public Enumeration getEntryPaths(String path) { + Bundle current = systemBundle; + if (current == null) + return null; + return current.getEntryPaths(path); + } + + public Dictionary getHeaders() { + Bundle current = systemBundle; + if (current == null) + return null; + return current.getHeaders(); + } + + public Dictionary getHeaders(String locale) { + Bundle current = systemBundle; + if (current == null) + return null; + return current.getHeaders(locale); + } + + public long getLastModified() { + Bundle current = systemBundle; + if (current == null) + return System.currentTimeMillis(); + return current.getLastModified(); + } + + public String getLocation() { + return Constants.SYSTEM_BUNDLE_LOCATION; + } + + public ServiceReference[] getRegisteredServices() { + Bundle current = systemBundle; + if (current == null) + return null; + return current.getRegisteredServices(); + } + + public URL getResource(String name) { + Bundle current = systemBundle; + if (current == null) + return null; + return current.getResource(name); + } + + public Enumeration getResources(String name) throws IOException { + Bundle current = systemBundle; + if (current == null) + return null; + return current.getResources(name); + } + + public ServiceReference[] getServicesInUse() { + Bundle current = systemBundle; + if (current == null) + return null; + return current.getServicesInUse(); + } + + public int getState() { + Bundle current = systemBundle; + if (current == null) + return Bundle.INSTALLED; + return current.getState(); + } + + public String getSymbolicName() { + return FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME; + } + + public boolean hasPermission(Object permission) { + Bundle current = systemBundle; + if (current == null) + return false; + return current.hasPermission(permission); + } + + public Class loadClass(String name) throws ClassNotFoundException { + Bundle current = systemBundle; + if (current == null) + return null; + return current.loadClass(name); + } + + public void start(int options) throws BundleException { + start(); + } + + /** + * @throws BundleException + */ + public void start() throws BundleException { + Framework current = framework; + if (getState() == Bundle.ACTIVE) + return; + if (getState() != Bundle.STARTING) + current = internalInit(null); + current.startLevelManager.doSetStartLevel(1); + } + + public void stop(int options) throws BundleException { + stop(); + } + + public void stop() throws BundleException { + Bundle current = systemBundle; + if (current == null) + return; + current.stop(); + } + + public void uninstall() throws BundleException { + throw new BundleException(Msg.BUNDLE_SYSTEMBUNDLE_UNINSTALL_EXCEPTION); + } + + public void update() throws BundleException { + Bundle current = systemBundle; + if (current == null) + return; + current.update(); + } + + public void update(InputStream in) throws BundleException { + try { + in.close(); + } catch (IOException e) { + // nothing; just being nice + } + update(); + } + +} diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java index 18a2e1e20..9b03a696c 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java @@ -43,8 +43,10 @@ public class Framework implements EventDispatcher, EventPublisher, Runnable { private static final String CONTEXTCLASSLOADER_PARENT_BOOT = "boot"; //$NON-NLS-1$ private static final String CONTEXTCLASSLOADER_PARENT_FWK = "fwk"; //$NON-NLS-1$ - private static final String PROP_FRAMEWORK_THREAD = "osgi.framework.activeThreadType"; //$NON-NLS-1$ - private static final String THREAD_NORMAL = "normal"; //$NON-NLS-1$ + public static final String PROP_FRAMEWORK_THREAD = "osgi.framework.activeThreadType"; //$NON-NLS-1$ + public static final String THREAD_NORMAL = "normal"; //$NON-NLS-1$ + public static final String PROP_EQUINOX_SECURITY = "eclipse.security"; //$NON-NLS-1$ + public static final String SECURITY_OSGI = "osgi"; //$NON-NLS-1$ private static String J2SE = "J2SE-"; //$NON-NLS-1$ private static String JAVASE = "JavaSE-"; //$NON-NLS-1$ @@ -1359,13 +1361,13 @@ public class Framework implements EventDispatcher, EventPublisher, Runnable { * is set much later than we would like! */ protected void installSecurityManager() { - String securityManager = FrameworkProperties.getProperty("eclipse.security", FrameworkProperties.getProperty("java.security.manager")); //$NON-NLS-1$ //$NON-NLS-2$ + String securityManager = FrameworkProperties.getProperty(PROP_EQUINOX_SECURITY, FrameworkProperties.getProperty("java.security.manager")); //$NON-NLS-1$ if (securityManager != null) { SecurityManager sm = System.getSecurityManager(); if (sm == null) { if (securityManager.length() == 0) sm = new SecurityManager(); // use the default one from java - else if (securityManager.equals("osgi")) //$NON-NLS-1$ + else if (securityManager.equals(SECURITY_OSGI)) sm = new EquinoxSecurityManager(); // use an OSGi enabled manager that understands postponed conditions else { // try to use a specific classloader by classname @@ -1609,6 +1611,8 @@ public class Framework implements EventDispatcher, EventPublisher, Runnable { } private void initializeContextFinder() { + //if (true) + // return; Thread current = Thread.currentThread(); Throwable error = null; try { @@ -1873,4 +1877,12 @@ public class Framework implements EventDispatcher, EventPublisher, Runnable { boolean isForcedRestart() { return forcedRestart; } + + public void waitForStop(long timeout) throws InterruptedException { + synchronized (this) { + if (active) { + this.wait(timeout); + } + } + } } diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/OSGi.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/OSGi.java deleted file mode 100644 index 94c5e5798..000000000 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/OSGi.java +++ /dev/null @@ -1,107 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.osgi.framework.internal.core; - -import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; - -/** - * Main class for the OSGi framework. This class is used to start the framework for production use. - * Objects of this class represent an instance of the OSGi framework and - * can be used to control the framework. - */ -public class OSGi { - protected Framework framework; - - /** - * Constructs an OSGi object with the specified FrameworkAdaptor. - * This method creates an OSGi framework. - * - * @param adaptor An adaptor object for the framework to use. - */ - public OSGi(FrameworkAdaptor adaptor) { - framework = createFramework(adaptor); - } - - /** - * Destroy the OSGi framework. This method stops the framework if - * it has been started. All resources associated with the framework - * are release and the OSGi object is no longer usable. - * - */ - public void close() { - framework.close(); - } - - /** - * Start the framework. - * - * The framework is started as described in the OSGi Framework - * specification. - */ - public void launch() { - framework.launch(); - } - - /** - * Stop the framework. - * - * The framework is stopped as described in the OSGi Framework - * specification. - */ - public void shutdown() { - framework.shutdown(); - } - - /** - * This method returns the state of the OSGi framework. - * - * @return true of the framework is launched, false if shutdown. - */ - public boolean isActive() { - return (framework.isActive()); - } - - /** - * Retrieve the BundleContext for the system bundle. - * - * @return The system bundle's BundleContext. - */ - public org.osgi.framework.BundleContext getBundleContext() { - return (framework.systemBundle.getContext()); - } - - /** - * Create the internal framework object. - * This method can be overridden to create a secure framework. - * - * @param adaptor FrameworkAdaptor object for the framework. - * @return New Framework object. - */ - protected Framework createFramework(FrameworkAdaptor adaptor) { - return (new Framework(adaptor)); - } - - /** - * Display the banner to System.out. - * - */ - protected void displayBanner() { - System.out.println(); - System.out.print(Msg.ECLIPSE_OSGI_NAME); - System.out.print(" "); //$NON-NLS-1$ - System.out.println(Msg.ECLIPSE_OSGI_VERSION); - System.out.println(); - System.out.println(Msg.OSGI_VERSION); - System.out.println(); - System.out.println(Msg.ECLIPSE_COPYRIGHT); - } -} diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelManager.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelManager.java index 570448bc6..d931034f9 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelManager.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/StartLevelManager.java @@ -238,16 +238,6 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL } /** - * Internal method to allow the framework to be launched synchronously by calling the - * StartLevelListener worker calls directly - * - * This method does not return until all bundles that should be started are started - */ - protected void launch(int startlevel) { - doSetStartLevel(startlevel); - } - - /** * Internal method to shut down the framework synchronously by setting the startlevel to zero * and calling the StartLevelListener worker calls directly * @@ -263,33 +253,17 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL * @param newSL start level value * @param callerBundle - the bundle initiating the change in start level */ - private void doSetStartLevel(int newSL) { + void doSetStartLevel(int newSL) { synchronized (lock) { settingStartLevel = true; try { int tempSL = activeSL; - if (newSL > tempSL) { boolean launching = tempSL == 0; if (launching) { - /* Load all installed bundles */ - loadInstalledBundles(getInstalledBundles(framework.bundles, false)); - /* Start the system bundle */ - try { - framework.systemBundle.state = Bundle.STARTING; - framework.systemBundle.context.start(); - framework.publishBundleEvent(BundleEvent.STARTING, framework.systemBundle); - // TODO this technically should be done just before firing the STARTED event for the system bundle; - // TODO State is set to ACTIVE here because some depend on the the system bundle being in the ACTIVE state when they are starting - framework.systemBundle.state = Bundle.ACTIVE; - } catch (BundleException be) { - if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) { - Debug.println("SLL: Bundle resume exception: " + be.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(be.getNestedException() == null ? be : be.getNestedException()); - } - framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, be); - throw new RuntimeException(be.getMessage()); - } + // TODO this technically should be done just before firing the STARTED event for the system bundle; + // TODO State is set to ACTIVE here because some depend on the the system bundle being in the ACTIVE state when they are starting + framework.systemBundle.state = Bundle.ACTIVE; } for (int i = tempSL; i < newSL; i++) { if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) { @@ -311,6 +285,11 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL tempSL--; decFWSL(i - 1, sortedBundles); } + if (newSL == 0) { + // stop and unload all bundles + suspendAllBundles(framework.bundles); + unloadAllBundles(framework.bundles); + } } framework.publishFrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, framework.systemBundle, null); if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) { @@ -514,7 +493,7 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL * @param bundles - the bundles installed in the framework * @return A sorted array of bundles */ - private AbstractBundle[] getInstalledBundles(BundleRepository bundles, boolean sortByDependency) { + AbstractBundle[] getInstalledBundles(BundleRepository bundles, boolean sortByDependency) { /* make copy of bundles vector in case it is modified during launch */ AbstractBundle[] installedBundles; @@ -583,21 +562,6 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL } /** - * Load all bundles in the list - * @param installedBundles a list of bundles to load - */ - private void loadInstalledBundles(AbstractBundle[] installedBundles) { - - for (int i = 0; i < installedBundles.length; i++) { - AbstractBundle bundle = installedBundles[i]; - if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) { - Debug.println("SLL: Trying to load bundle " + bundle); //$NON-NLS-1$ - } - bundle.load(); - } - } - - /** * Resume all bundles in the launch list * @param launch a list of Bundle Objects to launch */ @@ -632,12 +596,9 @@ public class StartLevelManager implements EventDispatcher, EventListener, StartL saveActiveStartLevel(decToSL); - if (decToSL == 0) { // stopping the framework - // stop and unload all bundles - suspendAllBundles(framework.bundles); - unloadAllBundles(framework.bundles); + if (decToSL == 0) // stopping the framework return; - } + // just decrementing the active startlevel - framework is not shutting down // Do not check framework.isForcedRestart here because we want to stop the active bundles regardless. for (int i = shutdown.length - 1; i >= 0; i--) { diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemBundle.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemBundle.java index 36cb2be0f..9ddf22b7c 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemBundle.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/SystemBundle.java @@ -137,15 +137,12 @@ public class SystemBundle extends BundleHost { /** * Close the the Bundle's file. - * This method closes the BundleContext for the SystemBundle - * and sets the SystemBundle's state to UNINSTALLED. + * This method closes the BundleContext for the SystemBundle. * */ protected void close() { context.close(); context = null; - - state = UNINSTALLED; } /** @@ -202,8 +199,33 @@ public class SystemBundle extends BundleHost { /* initialize the startlevel service */ framework.startLevelManager.initialize(); - framework.startLevelManager.launch(framework.startLevelManager.getFrameworkStartLevel()); + /* Load all installed bundles */ + loadInstalledBundles(framework.startLevelManager.getInstalledBundles(framework.bundles, false)); + /* Start the system bundle */ + try { + framework.systemBundle.state = Bundle.STARTING; + framework.systemBundle.context.start(); + framework.publishBundleEvent(BundleEvent.STARTING, framework.systemBundle); + } catch (BundleException be) { + if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) { + Debug.println("SLL: Bundle resume exception: " + be.getMessage()); //$NON-NLS-1$ + Debug.printStackTrace(be.getNestedException() == null ? be : be.getNestedException()); + } + framework.publishFrameworkEvent(FrameworkEvent.ERROR, framework.systemBundle, be); + throw new RuntimeException(be.getMessage()); + } + + } + + private void loadInstalledBundles(AbstractBundle[] installedBundles) { + for (int i = 0; i < installedBundles.length; i++) { + AbstractBundle bundle = installedBundles[i]; + if (Debug.DEBUG && Debug.DEBUG_STARTLEVEL) { + Debug.println("SLL: Trying to load bundle " + bundle); //$NON-NLS-1$ + } + bundle.load(); + } } /** @@ -214,11 +236,11 @@ public class SystemBundle extends BundleHost { public void stop() { framework.checkAdminPermission(this, AdminPermission.EXECUTE); - if (state == ACTIVE) { + if ((state & (ACTIVE | STARTING)) != 0) { Thread shutdown = framework.secureAction.createThread(new Runnable() { public void run() { try { - framework.shutdown(); + framework.close(); } catch (Throwable t) { // allow the adaptor to handle this unexpected error framework.adaptor.handleRuntimeError(t); @@ -271,17 +293,17 @@ public class SystemBundle extends BundleHost { if (state == ACTIVE) { Thread restart = framework.secureAction.createThread(new Runnable() { public void run() { - String prevSLProp = FrameworkProperties.getProperty(Constants.OSGI_FRAMEWORKBEGINNINGSTARTLEVEL); - String sl = String.valueOf(framework.startLevelManager.getStartLevel()); - FrameworkProperties.setProperty(Constants.OSGI_FRAMEWORKBEGINNINGSTARTLEVEL, sl); + int sl = framework.startLevelManager.getStartLevel(); FrameworkProperties.setProperty(Constants.PROP_OSGI_RELAUNCH, ""); //$NON-NLS-1$ framework.shutdown(); + try { + framework.waitForStop(1000); + } catch (InterruptedException e) { + // ignore + } framework.launch(); + framework.startLevelManager.doSetStartLevel(sl); FrameworkProperties.clearProperty(Constants.PROP_OSGI_RELAUNCH); - if (prevSLProp == null) - FrameworkProperties.clearProperty(Constants.OSGI_FRAMEWORKBEGINNINGSTARTLEVEL); - else - FrameworkProperties.setProperty(Constants.OSGI_FRAMEWORKBEGINNINGSTARTLEVEL, prevSLProp); } }, "System Bundle Update"); //$NON-NLS-1$ diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/launcher/Launcher.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/launcher/Launcher.java deleted file mode 100644 index aa9d33af3..000000000 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/launcher/Launcher.java +++ /dev/null @@ -1,365 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2008 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.osgi.framework.launcher; - -import java.lang.reflect.Constructor; -import java.util.*; -import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; -import org.eclipse.osgi.framework.internal.core.*; -import org.eclipse.osgi.util.NLS; - -/** - * <p>This class provides an entry point for launching the OSGi framework. - * It configures the OSGi framework according to the command line arguments: - * <ul> - * <li><b>-con[sole][:<i>port</i>]</b><br> - * Starts the OSGi framework with a console window. Any command line arguments not recognized are passed - * to the console for it to execute. If a port is specified the console will listen on that - * port for commands. If no port is specified, the console will use System.in and System.out. - * </li> - * <li><b>-adaptor[:adaptor-name][adaptor-args]</b> - * <pre> - * [adaptor-name] := "" | fully qualified class name of the FrameworkAdapter - * [adaptor-args] := *( ":" [value]) - * [value] := [token] | [quoted-string] - * - * This allows - * - * -adaptor::"bundledir=c:\jarbundles":reset DefaultAdaptor is chosen with args[] {"bundledir=c:\jarbundles", "reset"} - * -adaptor:com.foo.MyAdaptor com.foo.MyAdaptor chosen with args[] {} - * </pre> - * <p>-adaptor specifies the implementation class for the FrameworkAdapter to be used. - * args contains a list of FrameworkAdaptor arguments, separated by ":". FrameworkAdaptor arguments - * format is defined by the adaptor implementation class. They - * are passed to the adaptor class as an array of Strings. - * Example arguments used by the DefaultAdaptor are: - * <ul> - * <li>"bundledir=<i>directory"</i>. The directory to be used by the adaptor to store data. - * <li>reset</i>. Perform the reset action to clear the bundledir. - * <p>Actions can be defined by an adaptor. Multiple actions can be specified, - * separated by ":". - * </ul> - * <p>It is up to the adaptor implementation to define reasonable defaults if it's required - * arguments are not specified. - * <p>If -adaptor is not specified, or if no adaptor classname is specified, DefaultAdaptor will be - * used, which is file based and stores the files in the \bundles directory - * relative to the current directory. - * </ul> - * <li>-app[lication]:application-args - * <pre> - * [application-args] := *( ":" [value]) - * [value] := [token] | [quoted-string] - * </pre> - * <p>This argument allows arguments to be passed to specific applications at launch time. This is for eclipse - * plugins installed as applications. The arguments are as Eclipse currently needs them - one list of key=value pairs - * which are parsed by the applications. The application peels off only the args that apply to it. Others are ignored. - * </li> - * <p> - * Any other command line arguments are passed on to the console window - * of the framework if started with the -console option. If the console is not started, - * any unrecognized arguments will be ignored and a message displayed. - * <p> - * If none of the options above are specified, the OSGi framework is started: - * <ul> - * <li>with the Default FrameworkAdaptor - * <li>without a console window - * <li>without the remote agent - * </ul> - * @since 3.1 - */ -public class Launcher { - - /** default console port */ - protected String consolePort = ""; //$NON-NLS-1$ - - /** flag to indicate whether or not to start the console */ - protected boolean console = false; - - /** string containing the classname of the adaptor to be used in this framework instance */ - protected String adaptorClassName = "org.eclipse.osgi.baseadaptor.BaseAdaptor"; //$NON-NLS-1$ - - protected final String osgiConsoleClazz = "org.eclipse.osgi.framework.internal.core.FrameworkConsole"; //$NON-NLS-1$ - - /** array of adaptor arguments to be passed to FrameworkAdaptor.initialize() */ - protected String[] adaptorArgs = null; - - /* Components that can be installed and activated optionally. */ - private static final String OSGI_CONSOLE_COMPONENT_NAME = "OSGi Console"; //$NON-NLS-1$ - private static final String OSGI_CONSOLE_COMPONENT = "console.jar"; //$NON-NLS-1$ - - /** - * main method for Launcher. This method creates an Launcher object - * and kicks off the actual launch of a Framework instance. - * - * @param args The command line arguments - */ - public static void main(String args[]) { - - new Launcher().doIt(args); - - } - - /** - * Default constructor. Nothing at all to do here. - */ - public Launcher() { - // do nothing; - } - - /** - * Performs the actual launch based on the command line arguments - * - * @param args The command line arguments - */ - protected void doIt(String[] args) { - // set the compatibility boot delegation flag to false to get "standard" OSGi behavior WRT boot delegation (bug 178477) - if (FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION) == null) - FrameworkProperties.setProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "false"); //$NON-NLS-1$ - String[] consoleArgs = parseArgs(args); - - FrameworkAdaptor adaptor = null; - try { - adaptor = doAdaptor(); - } catch (Exception e) { - System.out.println(Msg.LAUNCHER_ADAPTOR_ERROR); - e.printStackTrace(); - return; - } - - OSGi osgi = doOSGi(adaptor); - if (osgi != null) { - if (console) { - doConsole(osgi, consoleArgs); - } else { - osgi.launch(); - } - } - } - - /** - * Parses the command line arguments and remembers them so they can be processed later. - * - * @param args The command line arguments - * @return String [] Any arguments that should be passed to the console - */ - protected String[] parseArgs(String[] args) { - Vector consoleArgsVector = new Vector(); - for (int i = 0; i < args.length; i++) { - boolean match = false; - - // Have to check for args that may be contained in double quotes but broken up by spaces - for example - // -adaptor::"bundledir=c:/my bundle dir":reset should all be one arg, but java breaks it into 3 args, - // ignoring the quotes. Must put it back together into one arg. - String fullarg = args[i]; - int quoteidx = fullarg.indexOf("\""); //$NON-NLS-1$ - if (quoteidx > 0) { - if (quoteidx == fullarg.lastIndexOf("\"")) { //$NON-NLS-1$ - boolean stillparsing = true; - i++; - while (i < args.length && stillparsing) { - fullarg = fullarg + " " + args[i]; //$NON-NLS-1$ - i++; - if (quoteidx < fullarg.lastIndexOf("\"")) { //$NON-NLS-1$ - stillparsing = false; - } - } - } - } else { - // IDE can't pass double quotes due to known eclipse bug (see Bugzilla 93201). Allowing for use of single quotes. - quoteidx = fullarg.indexOf("'"); //$NON-NLS-1$ - if (quoteidx > 0) { - if (quoteidx == fullarg.lastIndexOf("'")) { //$NON-NLS-1$ - boolean stillparsing = true; - i++; - while (i < args.length && stillparsing) { - fullarg = fullarg + " " + args[i]; //$NON-NLS-1$ - i++; - if (quoteidx < fullarg.lastIndexOf("'")) { //$NON-NLS-1$ - stillparsing = false; - } - } - } - fullarg = fullarg.replace('\'', '\"'); - } - } - - Tokenizer tok = new Tokenizer(fullarg); - if (tok.hasMoreTokens()) { - String command = tok.getString(" "); //$NON-NLS-1$ - StringTokenizer subtok = new StringTokenizer(command, ":"); //$NON-NLS-1$ - String subcommand = subtok.nextToken().toLowerCase(); - - if (matchCommand("-console", subcommand, 4)) { //$NON-NLS-1$ - _console(command); - match = true; - } - if (matchCommand("-adaptor", subcommand, 2)) { //$NON-NLS-1$ - _adaptor(command); - match = true; - } - if (match == false) { - // if the command doesn't match any of the known commands, save it to pass - // to the console - consoleArgsVector.addElement(fullarg); - } - } - } - // convert arguments to be passed to console into a string array for the Console - String[] consoleArgsArray = new String[consoleArgsVector.size()]; - Enumeration e = consoleArgsVector.elements(); - for (int i = 0; i < consoleArgsArray.length; i++) { - consoleArgsArray[i] = (String) e.nextElement(); - } - return consoleArgsArray; - } - - public static boolean matchCommand(String command, String input, int minLength) { - if (minLength <= 0) { - minLength = command.length(); - } - - int length = input.length(); - - if (minLength > length) { - length = minLength; - } - - return (command.regionMatches(0, input, 0, length)); - } - - /** - * Remembers that the -console option has been requested. - */ - protected void _console(String command) { - console = true; - StringTokenizer tok = new StringTokenizer(command, ":"); //$NON-NLS-1$ - // first token is always "-console" - tok.nextToken(); - if (tok.hasMoreTokens()) { - consolePort = tok.nextToken(); - } - } - - /** - * Remembers that the -adaptor option has been requested. Parses off the adaptor class - * file name, the adaptor file name, and the size if they are there. - * - * @param command The rest of the -adaptor parameter string that contains the class file name, - * and possibly the adaptor file and file size. - */ - protected void _adaptor(String command) { - Tokenizer tok = new Tokenizer(command); - // first token is always "-adaptor" - tok.getToken(":"); //$NON-NLS-1$ - tok.getChar(); // advance to next token - // and next token is either adaptor class name or ":" if we should use the default adaptor - String adp = tok.getToken(":"); //$NON-NLS-1$ - if (adp != null && adp.length() > 0) { - adaptorClassName = adp; - } - - // The following tokens are arguments to be processed by the adaptor implementation class. - // They may be enclosed in quotes. - // Store them in a vector until we know how many there are. - Vector v = new Vector(); - parseloop: while (true) { - tok.getChar(); // advance to next token - String arg = tok.getString(":"); //$NON-NLS-1$ - if (arg == null) - break parseloop; - v.addElement(arg); - } - // now that we know how many args there are, move args from vector to String[] - if (v != null) { - int numArgs = v.size(); - adaptorArgs = new String[numArgs]; - Enumeration e = v.elements(); - for (int i = 0; i < numArgs; i++) { - adaptorArgs[i] = (String) e.nextElement(); - } - } - } - - /** - * Processes the -adaptor command line argument. - * - * Parses the arguments to get the adaptor class name, the adaptor dir or filename, - * and the adaptor file size. - * - * @return a FrameworkAdaptor object - */ - protected FrameworkAdaptor doAdaptor() throws Exception { - - Class adaptorClass = Class.forName(adaptorClassName); - Class[] constructorArgs = new Class[] {String[].class}; - Constructor constructor = adaptorClass.getConstructor(constructorArgs); - return (FrameworkAdaptor) constructor.newInstance(new Object[] {adaptorArgs}); - } - - /** - * Creates the OSGi framework object. - * - * @param adaptor The FrameworkAdaptor object - */ - private OSGi doOSGi(FrameworkAdaptor adaptor) { - return new OSGi(adaptor); - } - - /** - * Invokes the OSGi Console on another thread - * - * @param osgi The current OSGi instance for the console to attach to - * @param consoleArgs An String array containing commands from the command line - * for the console to execute - */ - private void doConsole(OSGi osgi, String[] consoleArgs) { - - Constructor consoleConstructor; - Object osgiconsole; - Class[] parameterTypes; - Object[] parameters; - - try { - Class osgiconsoleClass = Class.forName(osgiConsoleClazz); - if (consolePort.length() == 0) { - parameterTypes = new Class[] {OSGi.class, String[].class}; - parameters = new Object[] {osgi, consoleArgs}; - } else { - parameterTypes = new Class[] {OSGi.class, int.class, String[].class}; - parameters = new Object[] {osgi, new Integer(consolePort), consoleArgs}; - } - consoleConstructor = osgiconsoleClass.getConstructor(parameterTypes); - osgiconsole = consoleConstructor.newInstance(parameters); - - Thread t = new Thread(((Runnable) osgiconsole), OSGI_CONSOLE_COMPONENT_NAME); - t.start(); - } catch (NumberFormatException nfe) { - System.err.println(NLS.bind(Msg.LAUNCHER_INVALID_PORT, consolePort)); - } catch (Exception ex) { - informAboutMissingComponent(OSGI_CONSOLE_COMPONENT_NAME, OSGI_CONSOLE_COMPONENT); - } - - } - - /** - * Informs the user about a missing component. - * - * @param component The name of the component - * @param jar The jar file that contains the component - */ - void informAboutMissingComponent(String component, String jar) { - System.out.println(); - System.out.print(NLS.bind(Msg.LAUNCHER_COMPONENT_MISSING, component)); - System.out.println(NLS.bind(Msg.LAUNCHER_COMPONENT_JAR, jar)); - System.out.println(); - } -} diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/launch/Equinox.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/launch/Equinox.java new file mode 100644 index 000000000..0b677e8c9 --- /dev/null +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/launch/Equinox.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright (c) 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgi.launch; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; +import org.eclipse.osgi.framework.internal.core.FrameworkProperties; +import org.osgi.framework.*; +import org.osgi.framework.launch.SystemBundle; + +/** + * @since 3.5 + */ +public class Equinox implements SystemBundle { + private static final String implName = "org.eclipse.osgi.framework.internal.core.EquinoxSystemBundle"; + /**@GuardedBy this*/ + private SystemBundle impl; + private final boolean useSeparateCL; + + public Equinox() { + useSeparateCL = FrameworkProperties.inUse(); + } + + private SystemBundle createImpl() { + try { + Class implClazz = getImplClass(); + return (SystemBundle) implClazz.newInstance(); + } catch (ClassNotFoundException e) { + throw new NoClassDefFoundError(implName); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.getMessage()); + } catch (InstantiationException e) { + throw new RuntimeException(e.getMessage()); + } + } + + private Class getImplClass() throws ClassNotFoundException { + ClassLoader thisCL = this.getClass().getClassLoader(); + if (!(useSeparateCL && (thisCL instanceof URLClassLoader))) + return Class.forName(implName); + URL[] cp = ((URLClassLoader) thisCL).getURLs(); + EquinoxFWClassLoader fwCL = new EquinoxFWClassLoader(cp, thisCL); + return fwCL.loadClass(implName); + } + + private synchronized SystemBundle getImpl() { + if (impl == null) + impl = createImpl(); + return impl; + } + + public void init(Properties configuration) { + if ((getState() & (Bundle.ACTIVE | Bundle.STARTING)) != 0) + throw new IllegalStateException("Framework is active!!"); + synchronized (this) { + if (impl != null && impl.getState() != Bundle.INSTALLED) { + try { + impl.stop(); + impl.waitForStop(30000); // timeout after 30 seconds + } catch (BundleException e) { + // ignore + } catch (InterruptedException e) { + // continue + } + impl = null; + } + } + getImpl().init(configuration); + } + + public void waitForStop(long timeout) throws InterruptedException { + getImpl().waitForStop(timeout); + } + + public Enumeration findEntries(String path, String filePattern, boolean recurse) { + return getImpl().findEntries(path, filePattern, recurse); + } + + public BundleContext getBundleContext() { + return getImpl().getBundleContext(); + } + + public long getBundleId() { + return getImpl().getBundleId(); + } + + public URL getEntry(String path) { + return getImpl().getEntry(path); + } + + public Enumeration getEntryPaths(String path) { + return getImpl().getEntryPaths(path); + } + + public Dictionary getHeaders() { + return getImpl().getHeaders(); + } + + public Dictionary getHeaders(String locale) { + return getImpl().getHeaders(locale); + } + + public long getLastModified() { + return getImpl().getLastModified(); + } + + public String getLocation() { + return getImpl().getLocation(); + } + + public ServiceReference[] getRegisteredServices() { + return getImpl().getRegisteredServices(); + } + + public URL getResource(String name) { + return getImpl().getResource(name); + } + + public Enumeration getResources(String name) throws IOException { + return getImpl().getResources(name); + } + + public ServiceReference[] getServicesInUse() { + return getImpl().getServicesInUse(); + } + + public int getState() { + return getImpl().getState(); + } + + public String getSymbolicName() { + return getImpl().getSymbolicName(); + } + + public boolean hasPermission(Object permission) { + return getImpl().hasPermission(permission); + } + + public Class loadClass(String name) throws ClassNotFoundException { + return getImpl().loadClass(name); + } + + public void start(int options) throws BundleException { + getImpl().start(options); + } + + public void start() throws BundleException { + getImpl().start(); + } + + public void stop(int options) throws BundleException { + getImpl().stop(options); + } + + public void stop() throws BundleException { + getImpl().stop(); + } + + public void uninstall() throws BundleException { + getImpl().uninstall(); + } + + public void update() throws BundleException { + getImpl().update(); + } + + public void update(InputStream in) throws BundleException { + getImpl().update(in); + } + +} diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/launch/EquinoxFWClassLoader.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/launch/EquinoxFWClassLoader.java new file mode 100644 index 000000000..45a763c48 --- /dev/null +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/launch/EquinoxFWClassLoader.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.osgi.launch; + +import java.net.URL; +import java.net.URLClassLoader; + +class EquinoxFWClassLoader extends URLClassLoader { + + private static final String[] DELEGATE_PARENT = {"org.osgi.", "org.eclipse.osgi.launch.", "org.eclipse.osgi.service."}; + private static final String[] SKIP_PARENT = {"org.osgi.framework.AdminPermission", "org.osgi.framework.FrameworkUtil", "org.osgi.service.condpermadmin.BundleSignerCondition",}; + + private final ClassLoader parent; + + public EquinoxFWClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + this.parent = parent; + } + + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + Class clazz = findLoadedClass(name); + if (clazz != null) + return clazz; + + boolean childFirst = childFirst(name); + ClassNotFoundException cnfe = null; + + if (childFirst) + try { + clazz = findClass(name); + } catch (ClassNotFoundException e) { + // continue + cnfe = e; + } + + if (clazz == null) + try { + clazz = parent.loadClass(name); + } catch (ClassNotFoundException e) { + // continue + } + + if (clazz == null && cnfe != null) + throw cnfe; + if (clazz == null && !childFirst) + clazz = findClass(name); + + if (resolve) + resolveClass(clazz); + return clazz; + } + + private boolean childFirst(String name) { + for (int i = SKIP_PARENT.length - 1; i >= 0; i--) + if (name.startsWith(SKIP_PARENT[i])) + return true; + for (int i = DELEGATE_PARENT.length - 1; i >= 0; i--) + if (name.startsWith(DELEGATE_PARENT[i])) + return false; + return true; + + } +} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseStarter.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseStarter.java index 9b2fc9359..26d30478b 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseStarter.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseStarter.java @@ -58,7 +58,7 @@ public class EclipseStarter { private static boolean initialize = false; public static boolean debug = false; private static boolean running = false; - private static OSGi osgi = null; + private static Framework framework = null; private static ServiceRegistration defaultMonitorRegistration = null; private static ServiceRegistration appLauncherRegistration = null; private static ServiceRegistration splashStreamRegistration = null; @@ -270,7 +270,7 @@ public class EclipseStarter { Profile.logEnter("EclipseStarter.startup()", null); //$NON-NLS-1$ if (running) throw new IllegalStateException(EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING); - initializeProperties(); + FrameworkProperties.initializeProperties(); processCommandLine(args); LocationManager.initializeLocations(); loadConfigurationInfo(); @@ -283,46 +283,30 @@ public class EclipseStarter { log = adaptor.getFrameworkLog(); if (Profile.PROFILE && Profile.STARTUP) Profile.logTime("EclipseStarter.startup()", "adapter created"); //$NON-NLS-1$ //$NON-NLS-2$ - osgi = new OSGi(adaptor); + framework = new Framework(adaptor); if (Profile.PROFILE && Profile.STARTUP) Profile.logTime("EclipseStarter.startup()", "OSGi created"); //$NON-NLS-1$ //$NON-NLS-2$ - context = osgi.getBundleContext(); + context = framework.getBundle(0).getBundleContext(); registerFrameworkShutdownHandlers(); publishSplashScreen(endSplashHandler); if (Profile.PROFILE && Profile.STARTUP) Profile.logTime("EclipseStarter.startup()", "osgi launched"); //$NON-NLS-1$ //$NON-NLS-2$ String consolePort = FrameworkProperties.getProperty(PROP_CONSOLE); if (consolePort != null) { - startConsole(osgi, new String[0], consolePort); + startConsole(framework, new String[0], consolePort); if (Profile.PROFILE && Profile.STARTUP) Profile.logTime("EclipseStarter.startup()", "console started"); //$NON-NLS-1$ //$NON-NLS-2$ } - final Bundle[][] startBundles = new Bundle[1][]; - final long[] stateStamp = {0l}; - BundleListener loadBundleListener = new SynchronousBundleListener() { - public void bundleChanged(BundleEvent event) { - if ((event.getType() & BundleEvent.STARTING) == 0 || event.getBundle().getBundleId() != 0) - return; - // save the cached timestamp before loading basic bundles; this is needed so we can do a proper timestamp check when logging resolver errors - stateStamp[0] = adaptor.getState().getTimeStamp(); - startBundles[0] = loadBasicBundles(); - } - }; - context.addBundleListener(loadBundleListener); - try { - osgi.launch(); - } finally { - context.removeBundleListener(loadBundleListener); - } + framework.launch(); + // save the cached timestamp before loading basic bundles; this is needed so we can do a proper timestamp check when logging resolver errors + long stateStamp = adaptor.getState().getTimeStamp(); + Bundle[] startBundles = loadBasicBundles(); - if (startBundles[0] == null) { + if (startBundles == null || ("true".equals(FrameworkProperties.getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false)))) { //$NON-NLS-1$ waitForShutdown(); return context; // cannot continue; loadBasicBundles caused refreshPackages to shutdown the framework } - if ("true".equals(FrameworkProperties.getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false))) { //$NON-NLS-1$ - waitForShutdown(); - return context; // cannot continue; refreshPackages shutdown the framework - } + if (Profile.PROFILE && Profile.STARTUP) Profile.logTime("EclipseStarter.startup()", "loading basic bundles"); //$NON-NLS-1$ //$NON-NLS-2$ @@ -332,10 +316,10 @@ public class EclipseStarter { if (Profile.PROFILE && Profile.STARTUP) Profile.logTime("EclipseStarter.startup()", "StartLevel set"); //$NON-NLS-1$ //$NON-NLS-2$ // they should all be active by this time - ensureBundlesActive(startBundles[0]); + ensureBundlesActive(startBundles); if (debug || FrameworkProperties.getProperty(PROP_DEV) != null) // only spend time showing unresolved bundles in dev/debug mode and the state has changed - if (stateStamp[0] != adaptor.getState().getTimeStamp()) + if (stateStamp != adaptor.getState().getTimeStamp()) logUnresolvedBundles(context.getBundles()); running = true; if (Profile.PROFILE && Profile.STARTUP) @@ -406,7 +390,7 @@ public class EclipseStarter { * @throws Exception if anything goes wrong */ public static void shutdown() throws Exception { - if (!running || osgi == null) + if (!running || framework == null) return; if (appLauncherRegistration != null) appLauncherRegistration.unregister(); @@ -421,8 +405,8 @@ public class EclipseStarter { splashStreamRegistration = null; defaultMonitorRegistration = null; stopConsole(); - osgi.close(); - osgi = null; + framework.close(); + framework = null; context = null; running = false; } @@ -743,7 +727,7 @@ public class EclipseStarter { // wait for the system bundle to stop Bundle systemBundle = context.getBundle(0); int i = 0; - while (i < 5000 && (systemBundle.getState() & (Bundle.ACTIVE | Bundle.STOPPING)) != 0) { + while (i < 5000 && (systemBundle.getState() & (Bundle.STARTING | Bundle.ACTIVE | Bundle.STOPPING)) != 0) { i += 200; try { Thread.sleep(200); @@ -761,17 +745,17 @@ public class EclipseStarter { * for the console to execute * @param consolePort the port on which to run the console. Empty string implies the default port. */ - private static void startConsole(OSGi equinox, String[] consoleArgs, String consolePort) { + private static void startConsole(Framework equinox, String[] consoleArgs, String consolePort) { try { String consoleClassName = FrameworkProperties.getProperty(PROP_CONSOLE_CLASS, DEFAULT_CONSOLE_CLASS); Class consoleClass = Class.forName(consoleClassName); Class[] parameterTypes; Object[] parameters; if (consolePort.length() == 0) { - parameterTypes = new Class[] {OSGi.class, String[].class}; + parameterTypes = new Class[] {Framework.class, String[].class}; parameters = new Object[] {equinox, consoleArgs}; } else { - parameterTypes = new Class[] {OSGi.class, int.class, String[].class}; + parameterTypes = new Class[] {Framework.class, int.class, String[].class}; parameters = new Object[] {equinox, new Integer(consolePort), consoleArgs}; } Constructor constructor = consoleClass.getConstructor(parameterTypes); @@ -1429,26 +1413,6 @@ public class EclipseStarter { return ((String) left[3]).compareTo((String) right[3]); // compare qualifier } - private static void initializeProperties() { - // initialize some framework properties that must always be set - if (FrameworkProperties.getProperty(PROP_FRAMEWORK) == null || FrameworkProperties.getProperty(PROP_INSTALL_AREA) == null) { - CodeSource cs = EclipseStarter.class.getProtectionDomain().getCodeSource(); - if (cs == null) - throw new IllegalArgumentException(NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_PROPS_NOT_SET, PROP_FRAMEWORK + ", " + PROP_INSTALL_AREA)); //$NON-NLS-1$ - URL url = cs.getLocation(); - // allow props to be preset - if (FrameworkProperties.getProperty(PROP_FRAMEWORK) == null) - FrameworkProperties.setProperty(PROP_FRAMEWORK, url.toExternalForm()); - if (FrameworkProperties.getProperty(PROP_INSTALL_AREA) == null) { - String filePart = url.getFile(); - FrameworkProperties.setProperty(PROP_INSTALL_AREA, filePart.substring(0, filePart.lastIndexOf('/'))); - } - } - // always decode these properties - FrameworkProperties.setProperty(PROP_FRAMEWORK, decode(FrameworkProperties.getProperty(PROP_FRAMEWORK))); - FrameworkProperties.setProperty(PROP_INSTALL_AREA, decode(FrameworkProperties.getProperty(PROP_INSTALL_AREA))); - } - private static void finalizeProperties() { // if check config is unknown and we are in dev mode, if (FrameworkProperties.getProperty(PROP_DEV) != null && FrameworkProperties.getProperty(PROP_CHECK_CONFIG) == null) @@ -1469,102 +1433,6 @@ public class EclipseStarter { } } - private static String decode(String urlString) { - //try to use Java 1.4 method if available - try { - Class clazz = URLDecoder.class; - Method method = clazz.getDeclaredMethod("decode", new Class[] {String.class, String.class}); //$NON-NLS-1$ - //first encode '+' characters, because URLDecoder incorrectly converts - //them to spaces on certain class library implementations. - if (urlString.indexOf('+') >= 0) { - int len = urlString.length(); - StringBuffer buf = new StringBuffer(len); - for (int i = 0; i < len; i++) { - char c = urlString.charAt(i); - if (c == '+') - buf.append("%2B"); //$NON-NLS-1$ - else - buf.append(c); - } - urlString = buf.toString(); - } - Object result = method.invoke(null, new Object[] {urlString, "UTF-8"}); //$NON-NLS-1$ - if (result != null) - return (String) result; - } catch (Exception e) { - //JDK 1.4 method not found -- fall through and decode by hand - } - //decode URL by hand - boolean replaced = false; - byte[] encodedBytes = urlString.getBytes(); - int encodedLength = encodedBytes.length; - byte[] decodedBytes = new byte[encodedLength]; - int decodedLength = 0; - for (int i = 0; i < encodedLength; i++) { - byte b = encodedBytes[i]; - if (b == '%') { - byte enc1 = encodedBytes[++i]; - byte enc2 = encodedBytes[++i]; - b = (byte) ((hexToByte(enc1) << 4) + hexToByte(enc2)); - replaced = true; - } - decodedBytes[decodedLength++] = b; - } - if (!replaced) - return urlString; - try { - return new String(decodedBytes, 0, decodedLength, "UTF-8"); //$NON-NLS-1$ - } catch (UnsupportedEncodingException e) { - //use default encoding - return new String(decodedBytes, 0, decodedLength); - } - } - - private static int hexToByte(byte b) { - switch (b) { - case '0' : - return 0; - case '1' : - return 1; - case '2' : - return 2; - case '3' : - return 3; - case '4' : - return 4; - case '5' : - return 5; - case '6' : - return 6; - case '7' : - return 7; - case '8' : - return 8; - case '9' : - return 9; - case 'A' : - case 'a' : - return 10; - case 'B' : - case 'b' : - return 11; - case 'C' : - case 'c' : - return 12; - case 'D' : - case 'd' : - return 13; - case 'E' : - case 'e' : - return 14; - case 'F' : - case 'f' : - return 15; - default : - throw new IllegalArgumentException("Switch error decoding URL"); //$NON-NLS-1$ - } - } - /** * Sets the initial properties for the platform. * This method must be called before calling the {@link #run(String[], Runnable)} or diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/core/FrameworkProperties.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/core/FrameworkProperties.java index 12147bd0e..8455f820f 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/core/FrameworkProperties.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/core/FrameworkProperties.java @@ -8,8 +8,14 @@ *******************************************************************************/ package org.eclipse.osgi.framework.internal.core; -import java.util.Properties; -import java.util.PropertyPermission; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLDecoder; +import java.security.CodeSource; +import java.util.*; +import org.eclipse.core.runtime.internal.adaptor.EclipseAdaptorMsg; +import org.eclipse.osgi.util.NLS; /* * This class should be used in ALL places in the framework implementation to get "system" properties. @@ -17,34 +23,21 @@ import java.util.PropertyPermission; */ public class FrameworkProperties { + /**@GuardedBy FrameworkProperties.class*/ private static Properties properties; // A flag of some sort will have to be supported. // Many existing plugins get framework propeties directly from System instead of BundleContext. // Note that the OSGi TCK is one example where this property MUST be set to false because many TCK bundles set and read system properties. private static final String USING_SYSTEM_PROPERTIES_KEY = "osgi.framework.useSystemProperties"; //$NON-NLS-1$ - - static { - Properties systemProperties = System.getProperties(); - String usingSystemProperties = systemProperties.getProperty(USING_SYSTEM_PROPERTIES_KEY); - if (usingSystemProperties == null || usingSystemProperties.equalsIgnoreCase(Boolean.TRUE.toString())) { - properties = systemProperties; - } else { - // use systemProperties for a snapshot - // also see requirements in Bundlecontext.getProperty(...)) - properties = new Properties(); - // snapshot of System properties for uses of getProperties who expect to see framework properties set as System properties - // we need to do this for all system properties because the properties object is used to back - // BundleContext#getProperty method which expects all system properties to be available - properties.putAll(systemProperties); - } - } + private static final String PROP_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$ + private static final String PROP_INSTALL_AREA = "osgi.install.area"; //$NON-NLS-1$ public static Properties getProperties() { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPropertiesAccess(); - return properties; + return internalGetProperties(null); } public static String getProperty(String key) { @@ -55,20 +48,183 @@ public class FrameworkProperties { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPropertyAccess(key); - return properties.getProperty(key, defaultValue); + return internalGetProperties(null).getProperty(key, defaultValue); } public static String setProperty(String key, String value) { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(new PropertyPermission(key, "write")); //$NON-NLS-1$ - return (String) properties.put(key, value); + return (String) internalGetProperties(null).put(key, value); } public static String clearProperty(String key) { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(new PropertyPermission(key, "write")); //$NON-NLS-1$ - return (String) properties.remove(key); + return (String) internalGetProperties(null).remove(key); + } + + private static synchronized Properties internalGetProperties(String usingSystemProperties) { + if (properties == null) { + Properties systemProperties = System.getProperties(); + if (usingSystemProperties == null) + usingSystemProperties = systemProperties.getProperty(USING_SYSTEM_PROPERTIES_KEY); + if (usingSystemProperties == null || usingSystemProperties.equalsIgnoreCase(Boolean.TRUE.toString())) { + properties = systemProperties; + } else { + // use systemProperties for a snapshot + // also see requirements in Bundlecontext.getProperty(...)) + properties = new Properties(); + // snapshot of System properties for uses of getProperties who expect to see framework properties set as System properties + // we need to do this for all system properties because the properties object is used to back + // BundleContext#getProperty method which expects all system properties to be available + properties.putAll(systemProperties); + } + } + return properties; + } + + public static synchronized void setProperties(Properties input) { + if (input == null) { + // just use internal props; note that this will reuse a previous set of properties if they were set + internalGetProperties("false"); //$NON-NLS-1$ + return; + } + properties = null; + Properties toSet = internalGetProperties("false"); //$NON-NLS-1$ + for (Enumeration keys = input.keys(); keys.hasMoreElements();) { + String key = (String) keys.nextElement(); + Object value = input.getProperty(key); + if (value != null) { + toSet.setProperty(key, (String) value); + continue; + } + value = input.get(key); + if (value != null) + toSet.put(key, value); + else + toSet.remove(key); + } + } + + public static synchronized boolean inUse() { + return properties != null; + } + + public static void initializeProperties() { + // initialize some framework properties that must always be set + if (getProperty(PROP_FRAMEWORK) == null || getProperty(PROP_INSTALL_AREA) == null) { + CodeSource cs = FrameworkProperties.class.getProtectionDomain().getCodeSource(); + if (cs == null) + throw new IllegalArgumentException(NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_PROPS_NOT_SET, PROP_FRAMEWORK + ", " + PROP_INSTALL_AREA)); //$NON-NLS-1$ + URL url = cs.getLocation(); + // allow props to be preset + if (getProperty(PROP_FRAMEWORK) == null) + setProperty(PROP_FRAMEWORK, url.toExternalForm()); + if (getProperty(PROP_INSTALL_AREA) == null) { + String filePart = url.getFile(); + setProperty(PROP_INSTALL_AREA, filePart.substring(0, filePart.lastIndexOf('/'))); + } + } + // always decode these properties + setProperty(PROP_FRAMEWORK, decode(getProperty(PROP_FRAMEWORK))); + setProperty(PROP_INSTALL_AREA, decode(getProperty(PROP_INSTALL_AREA))); + } + + public static String decode(String urlString) { + //try to use Java 1.4 method if available + try { + Class clazz = URLDecoder.class; + Method method = clazz.getDeclaredMethod("decode", new Class[] {String.class, String.class}); //$NON-NLS-1$ + //first encode '+' characters, because URLDecoder incorrectly converts + //them to spaces on certain class library implementations. + if (urlString.indexOf('+') >= 0) { + int len = urlString.length(); + StringBuffer buf = new StringBuffer(len); + for (int i = 0; i < len; i++) { + char c = urlString.charAt(i); + if (c == '+') + buf.append("%2B"); //$NON-NLS-1$ + else + buf.append(c); + } + urlString = buf.toString(); + } + Object result = method.invoke(null, new Object[] {urlString, "UTF-8"}); //$NON-NLS-1$ + if (result != null) + return (String) result; + } catch (Exception e) { + //JDK 1.4 method not found -- fall through and decode by hand + } + //decode URL by hand + boolean replaced = false; + byte[] encodedBytes = urlString.getBytes(); + int encodedLength = encodedBytes.length; + byte[] decodedBytes = new byte[encodedLength]; + int decodedLength = 0; + for (int i = 0; i < encodedLength; i++) { + byte b = encodedBytes[i]; + if (b == '%') { + byte enc1 = encodedBytes[++i]; + byte enc2 = encodedBytes[++i]; + b = (byte) ((hexToByte(enc1) << 4) + hexToByte(enc2)); + replaced = true; + } + decodedBytes[decodedLength++] = b; + } + if (!replaced) + return urlString; + try { + return new String(decodedBytes, 0, decodedLength, "UTF-8"); //$NON-NLS-1$ + } catch (UnsupportedEncodingException e) { + //use default encoding + return new String(decodedBytes, 0, decodedLength); + } + } + + private static int hexToByte(byte b) { + switch (b) { + case '0' : + return 0; + case '1' : + return 1; + case '2' : + return 2; + case '3' : + return 3; + case '4' : + return 4; + case '5' : + return 5; + case '6' : + return 6; + case '7' : + return 7; + case '8' : + return 8; + case '9' : + return 9; + case 'A' : + case 'a' : + return 10; + case 'B' : + case 'b' : + return 11; + case 'C' : + case 'c' : + return 12; + case 'D' : + case 'd' : + return 13; + case 'E' : + case 'e' : + return 14; + case 'F' : + case 'f' : + return 15; + default : + throw new IllegalArgumentException("Switch error decoding URL"); //$NON-NLS-1$ + } } } |