diff options
author | Thomas Watson | 2006-02-02 21:08:39 +0000 |
---|---|---|
committer | Thomas Watson | 2006-02-02 21:08:39 +0000 |
commit | 452a71a4901410b0ed7259b2ce95d447787613ed (patch) | |
tree | 343d37e01ba71b48809c94e3f3cdb83c40040489 /bundles | |
parent | d46feca470c5042afa502ce9192917bed9fcf246 (diff) | |
download | rt.equinox.framework-452a71a4901410b0ed7259b2ce95d447787613ed.tar.gz rt.equinox.framework-452a71a4901410b0ed7259b2ce95d447787613ed.tar.xz rt.equinox.framework-452a71a4901410b0ed7259b2ce95d447787613ed.zip |
Bug 114968 Replace monolithic EclipseAdaptor impl with a hookable adaptorpost-bug114968-hooks
Diffstat (limited to 'bundles')
124 files changed, 8243 insertions, 7779 deletions
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/internal/plugins/InstallTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/internal/plugins/InstallTests.java index 83f2914e8..9fcf5d4d4 100644 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/internal/plugins/InstallTests.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/internal/plugins/InstallTests.java @@ -68,7 +68,7 @@ public class InstallTests extends TestCase { try { assertEquals("1.0", "bundle02", installed.getSymbolicName()); assertEquals("1.1", Bundle.INSTALLED, installed.getState()); - assertEquals("1.2", "2.0", installed.getHeaders().get(Constants.BUNDLE_VERSION)); + assertEquals("1.2", new Version("2.0"), new Version((String) installed.getHeaders().get(Constants.BUNDLE_VERSION))); } finally { // clean-up installed.uninstall(); diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/PlatformAdminTest.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/PlatformAdminTest.java index 26f645618..d71ddf1db 100644 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/PlatformAdminTest.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/PlatformAdminTest.java @@ -13,7 +13,6 @@ package org.eclipse.osgi.tests.services.resolver; import java.io.*; import junit.framework.Test; import junit.framework.TestSuite; -import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.service.resolver.State; import org.osgi.framework.BundleException; @@ -51,63 +50,6 @@ public class PlatformAdminTest extends AbstractStateTest { newState = original.getFactory().createState(original); assertEquals("2", original, newState); } - - public void testCommit() { - final String A1_LOCATION = "org.eclipse.a"; - final String A1_MANIFEST = "Bundle-SymbolicName: org.eclipse.a\n" + "Bundle-Version: 1.0.0\n" + "Export-Package: org.eclipse.package1,org.eclipse.package2\n" + ";Import-Package: org.eclipse.package3"; - final String B1_LOCATION = "org.eclipse.b"; - final String B1_MANIFEST = "Bundle-SymbolicName: org.eclipse.b\n" + "Bundle-Version: 1.0.0\n" + "Provide-Package: org.eclipse.b.package1,org.eclipse.b.package2,org.eclipse.b.package3\n" + "Export-Package: org.eclipse.package3"; - final String C1_LOCATION = "org.eclipse.c"; - final String C1_MANIFEST = "Bundle-SymbolicName: org.eclipse.c\n" + "Bundle-Version: 1.0.0\n" + "Required-Bundle: org.eclipse.b"; - final String D1_LOCATION = "org.eclipse.d"; - final String D1_MANIFEST = "Bundle-SymbolicName: org.eclipse.d\n" + "Bundle-Version: 1.0.0"; - State state = platformAdmin.getState(); - BundleDescription a1 = null; - BundleDescription b1 = null; - BundleDescription c1 = null; - BundleDescription d1 = null; - try { - a1 = state.getFactory().createBundleDescription(parseManifest(A1_MANIFEST), A1_LOCATION, 3); - b1 = state.getFactory().createBundleDescription(parseManifest(B1_MANIFEST), B1_LOCATION, 1); - c1 = state.getFactory().createBundleDescription(parseManifest(C1_MANIFEST), C1_LOCATION, 2); - d1 = state.getFactory().createBundleDescription(parseManifest(D1_MANIFEST), D1_LOCATION, 4); - } catch (BundleException e) { - fail("0.0", e); - } - state.addBundle(b1); - state.addBundle(c1); - assertEquals("0.5", 2, state.getBundles().length); - try { - platformAdmin.commit(state); - } catch (BundleException e) { - fail("1.0 - " + e.toString()); - } - assertEquals("2.0", 2, platformAdmin.getState().getBundles().length); - State staleState = platformAdmin.getState(); - state = platformAdmin.getState(); - state.addBundle(a1); - try { - platformAdmin.commit(state); - } catch (BundleException e) { - fail("3.0 - " + e.toString()); - } - assertEquals("4.0", 3, platformAdmin.getState().getBundles().length); - staleState.addBundle(d1); - try { - platformAdmin.commit(staleState); - fail("5.0"); - } catch (BundleException e) { - // that is ok, it should have failed - } - state = platformAdmin.getState(); - assertNotNull("5.9", state.removeBundle(1)); - try { - platformAdmin.commit(state); - } catch (BundleException e) { - fail("6.0 - " + e.toString()); - } - assertEquals("7.0", 2, platformAdmin.getState().getBundles().length); - } } //TODO tests to enable //testFragmentUpdateNoVersionChanged() diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/SimpleBundleInstaller.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/SimpleBundleInstaller.java deleted file mode 100644 index e5a41070a..000000000 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/SimpleBundleInstaller.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004 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.services.resolver; - -import org.eclipse.osgi.framework.adaptor.core.BundleInstaller; -import org.eclipse.osgi.service.resolver.BundleDescription; -import org.eclipse.osgi.service.resolver.State; -import org.osgi.framework.BundleException; - -public class SimpleBundleInstaller implements BundleInstaller { - private State state; - - public SimpleBundleInstaller(State state) { - this.state = state; - } - - public void installBundle(BundleDescription toInstall) throws BundleException { - state.addBundle(toInstall); - } - - public void uninstallBundle(BundleDescription toUninstall) throws BundleException { - state.removeBundle(toUninstall); - } - - public void updateBundle(BundleDescription toUpdate) throws BundleException { - //TODO - } -} diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/SimplePlatformAdmin.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/SimplePlatformAdmin.java index 8dd67e8fd..10b6aff1d 100644 --- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/SimplePlatformAdmin.java +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/services/resolver/SimplePlatformAdmin.java @@ -11,13 +11,12 @@ package org.eclipse.osgi.tests.services.resolver; import java.io.File; -import org.eclipse.osgi.framework.adaptor.core.StateManager; +import org.eclipse.osgi.internal.baseadaptor.StateManager; import org.osgi.framework.BundleContext; public class SimplePlatformAdmin extends StateManager { public SimplePlatformAdmin(File bundleRootDir, BundleContext context) { super(new File(bundleRootDir, ".state"), new File(bundleRootDir, ".lazy"), context); //$NON-NLS-1$//$NON-NLS-2$ createSystemState(); - setInstaller(new SimpleBundleInstaller(getSystemState())); } } diff --git a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF index a88f6c61d..8b43cb9e7 100644 --- a/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.osgi/META-INF/MANIFEST.MF @@ -1,44 +1,47 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
-Export-Package: org.osgi.framework; version=1.3,
- org.osgi.service.packageadmin; version=1.2,
- org.osgi.service.permissionadmin; version=1.2,
- org.osgi.service.condpermadmin; version=1.0,
- org.osgi.service.url; version=1.0,
- org.osgi.service.startlevel; version=1.0,
- org.osgi.util.tracker; version=1.3.1,
- org.eclipse.osgi.event; version=1.0,
- org.eclipse.osgi.framework.console; version=1.0,
- org.eclipse.osgi.framework.eventmgr; version=1.0,
- org.eclipse.osgi.framework.log; version=1.0,
- org.eclipse.osgi.service.debug; version=1.0,
- org.eclipse.osgi.service.datalocation; version=1.0,
- org.eclipse.osgi.service.environment; version=1.0,
- org.eclipse.osgi.service.localization; version=1.0,
- org.eclipse.osgi.service.pluginconversion; version=1.0,
- org.eclipse.osgi.service.resolver; version=1.0,
- org.eclipse.osgi.service.runnable; version=1.0,
- org.eclipse.osgi.service.urlconversion; version=1.0,
- org.eclipse.osgi.storagemanager; version=1.0,
- org.eclipse.osgi.util; version=1.0,
- org.eclipse.core.runtime.adaptor; x-friends:=org.eclipse.core.runtime,
- org.eclipse.core.runtime.internal.adaptor; x-internal:=true,
- org.eclipse.core.runtime.internal.stats; x-friends:="org.eclipse.core.runtime, org.eclipse.core.tools",
- org.eclipse.osgi.framework.adaptor; x-internal:=true,
- org.eclipse.osgi.framework.adaptor.core; x-internal:=true,
- org.eclipse.osgi.framework.debug; x-internal:=true,
- org.eclipse.osgi.framework.internal.core; x-internal:=true,
- org.eclipse.osgi.framework.internal.defaultadaptor; x-internal:=true,
- org.eclipse.osgi.framework.internal.protocol; x-internal:=true,
- org.eclipse.osgi.framework.internal.protocol.bundleentry; x-internal:=true,
- 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.module; x-internal:=true,
- org.eclipse.osgi.internal.resolver; x-internal:=true,
- org.eclipse.osgi.internal.profile; x-internal:=true
+Export-Package: org.eclipse.osgi.event;version="1.0",
+ org.eclipse.osgi.framework.console;version="1.0",
+ org.eclipse.osgi.framework.eventmgr;version="1.0",
+ org.eclipse.osgi.framework.log;version="1.0",
+ org.eclipse.osgi.service.datalocation;version="1.0",
+ org.eclipse.osgi.service.debug;version="1.0",
+ org.eclipse.osgi.service.environment;version="1.0",
+ org.eclipse.osgi.service.localization;version="1.0",
+ org.eclipse.osgi.service.pluginconversion;version="1.0",
+ org.eclipse.osgi.service.resolver;version="1.0",
+ org.eclipse.osgi.service.runnable;version="1.0",
+ org.eclipse.osgi.service.urlconversion;version="1.0",
+ org.eclipse.osgi.storagemanager;version="1.0",
+ org.eclipse.osgi.util;version="1.0",
+ org.osgi.framework;version="1.3",
+ org.osgi.service.condpermadmin;version="1.0",
+ org.osgi.service.packageadmin;version="1.2",
+ org.osgi.service.permissionadmin;version="1.2",
+ org.osgi.service.startlevel;version="1.0",
+ org.osgi.service.url;version="1.0",
+ org.osgi.util.tracker;version="1.3.1",
+ org.eclipse.core.runtime.adaptor;x-friends:="org.eclipse.core.runtime",
+ org.eclipse.core.runtime.internal.adaptor;x-internal:=true,
+ org.eclipse.core.runtime.internal.stats;x-friends:="org.eclipse.core.runtime,org.eclipse.core.tools",
+ org.eclipse.osgi.baseadaptor;x-internal:=true,
+ org.eclipse.osgi.baseadaptor.bundlefile;x-internal:=true,
+ org.eclipse.osgi.baseadaptor.hooks;x-internal:=true,
+ org.eclipse.osgi.baseadaptor.loader;x-internal:=true,
+ org.eclipse.osgi.framework.adaptor;x-internal:=true,
+ org.eclipse.osgi.framework.debug;x-internal:=true,
+ org.eclipse.osgi.framework.internal.core;x-internal:=true,
+ org.eclipse.osgi.framework.internal.protocol;x-internal:=true,
+ org.eclipse.osgi.framework.internal.protocol.bundleentry;x-internal:=true,
+ 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,
+ org.eclipse.osgi.internal.profile;x-internal:=true,
+ org.eclipse.osgi.internal.resolver;x-internal:=true
Export-Service: org.osgi.service.packageadmin.PackageAdmin,
org.osgi.service.permissionadmin.PermissionAdmin,
org.osgi.service.startlevel.StartLevel,
diff --git a/bundles/org.eclipse.osgi/build.properties b/bundles/org.eclipse.osgi/build.properties index 9b863e150..c452f644b 100644 --- a/bundles/org.eclipse.osgi/build.properties +++ b/bundles/org.eclipse.osgi/build.properties @@ -17,6 +17,7 @@ bin.includes = .options,\ META-INF/,\ systembundle.properties,\ *.profile,\ - profile.list + profile.list,\ + hookconfigurators.properties src.includes = about.html source.. = osgi/src, core/adaptor/, core/framework/, resolver/src/, defaultAdaptor/src/, eclipseAdaptor/src/, console/src/ diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleWatcher.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleWatcher.java index 99abf1cac..d11a76fcc 100644 --- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleWatcher.java +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/BundleWatcher.java @@ -13,8 +13,17 @@ package org.eclipse.osgi.framework.adaptor; import org.osgi.framework.Bundle; /** - * Contains information about activated bundles and acts as the main - * entry point for logging plugin activity. + * Watches bundle lifecyle processes. This interface is different than that of + * a BundleLisener because it gets notified before and after all lifecycle + * changes. A bundle watcher acts as the main entry point for logging + * bundle activity. + * <p> + * Note that a bundle watcher is always notified of when a lifecycle processes + * has ended even in cases where the lifecycle process may have failed. For + * example, if activating a bundle fails the {@link #END_ACTIVATION} flag will + * still be sent to the bundle watcher to notify them that the activation + * process has ended. + * </p> * <p> * Clients may implement this interface. * </p> @@ -22,14 +31,51 @@ import org.osgi.framework.Bundle; */ public interface BundleWatcher { /** - * Called when a bundle is being activated. - * @param bundle the bundle being activated. + * The install process is beginning for a bundle + */ + public static final int START_INSTALLING = 0x0001; + /** + * The install process has ended for a bundle + */ + public static final int END_INSTALLING = 0x0002; + /** + * The activation process is beginning for a bundle + */ + public static final int START_ACTIVATION = 0x0004; + /** + * The activation process has ended for a bundle + */ + public static final int END_ACTIVATION = 0x0008; + /** + * The deactivation process is beginning for a bundle + */ + public static final int START_DEACTIVATION = 0x0010; + /** + * The deactivation process has ended for a bundle + */ + public static final int END_DEACTIVATION = 0x0020; + /** + * The uninstallation process is beginning for a bundle + */ + public static final int START_UNINSTALLING = 0x0040; + /** + * The uninstallation process has ended for a bundle */ - public void startActivation(Bundle bundle); + public static final int END_UNINSTALLING = 0x0080; /** - * Called after a bundle has been activated. - * @param bundle the bundle being activated. + * Receives notification that a lifecycle change is going to start or has + * ended. + * @param bundle the bundle for which the lifecycle change is occurring on. + * @param type the type of lifecycle change which is occurring. + * @see #START_INSTALLING + * @see #END_INSTALLING + * @see #START_ACTIVATION + * @see #END_ACTIVATION + * @see #START_DEACTIVATION + * @see #END_DEACTIVATION + * @see #START_UNINSTALLING + * @see #END_UNINSTALLING */ - public void endActivation(Bundle bundle); + public void watchBundle(Bundle bundle, int type); } diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/FrameworkAdaptor.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/FrameworkAdaptor.java index 64718d9ce..442516cee 100644 --- a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/FrameworkAdaptor.java +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/adaptor/FrameworkAdaptor.java @@ -214,32 +214,6 @@ public interface FrameworkAdaptor { public void frameworkStopping(BundleContext context); /** - * Gets the value for Export-Package for packages that a FrameworkAdaptor is exporting - * to the framework. The String returned will be parsed by the framework - * and the packages specified will be exported by the System Bundle. - * @return The value for Export-Package that the System Bundle will export or - * null if none exist. - */ - public String getExportPackages(); - - /** - * Gets the value for Provide-Package for packages that a FrameworkAdaptor is exporting - * to the framework. The String returned will be parsed by the framework - * and the packages specified will be exported by the System Bundle. - * @return The value for Provide-Package that the System Bundle will export or - * null if none exist. - */ - public String getProvidePackages(); - - /** - * Gets any Service class names that a FrameworkAdaptor is exporting to the - * framework. The class names returned will be exported by the System Bundle. - * @return The value of Export-Service that the System Bundle will export or - * null if none exist - */ - public String getExportServices(); - - /** * Returns the initial bundle start level as maintained by this adaptor * @return the initial bundle start level */ diff --git a/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/KeyedElement.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/KeyedElement.java new file mode 100644 index 000000000..6f81a8043 --- /dev/null +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/KeyedElement.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2005 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.util; + +/** + * An element of an <code>KeyedHashSet</code>. A KeyedElement privides the key which is used to hash + * the elements in an <code>KeyedHashSet</code>. + * @see KeyedHashSet + */ +// This class was moved from /org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/KeyedElement.java +public interface KeyedElement { + /** + * Returns the hash code of the key + * @return the hash code of the key + */ + public int getKeyHashCode(); + + /** + * Compares this element with a specified element + * @param other the element to compare with + * @return returns true if the specified element equals this element + */ + public boolean compare(KeyedElement other); + + /** + * Returns the key for this element + * @return the key for this element + */ + public Object getKey(); +} diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/KeyedHashSet.java b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/KeyedHashSet.java index a1ed4f675..85a6e0417 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/KeyedHashSet.java +++ b/bundles/org.eclipse.osgi/core/adaptor/org/eclipse/osgi/framework/util/KeyedHashSet.java @@ -8,36 +8,63 @@ * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ -package org.eclipse.osgi.framework.internal.core; +package org.eclipse.osgi.framework.util; import java.util.Iterator; import java.util.NoSuchElementException; +/** + * A set data structure which only accepts {@link KeyedElement} objects as elements of the set. + * Unlike typical set implementations this set requires each element to provide its own key. This helps + * reduce the overhead of storing the keys of each individual element<p> + * This class in not thread safe, clients must ensure synchronization when modifying an object of this type. + */ +// This class was moved from /org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/KeyedHashSet.java public class KeyedHashSet { - protected static final int MINIMUM_SIZE = 7; - protected int elementCount = 0; - protected KeyedElement[] elements; - protected boolean replace; + public static final int MINIMUM_SIZE = 7; + int elementCount = 0; + KeyedElement[] elements; + private boolean replace; private int capacity; + /** + * Constructs an KeyedHashSet which allows elements to be replaced and with the minimum initial capacity. + */ public KeyedHashSet() { this(MINIMUM_SIZE, true); } + /** + * Constructs an KeyedHashSet with the minimum initial capacity. + * @param replace true if this set allows elements to be replaced + */ public KeyedHashSet(boolean replace) { this(MINIMUM_SIZE, replace); } + /** + * Constructs an KeyedHashSet which allows elements to be replaced. + * @param capacity the initial capacity of this set + */ public KeyedHashSet(int capacity) { this(capacity, true); } + /** + * Constructs an KeyedHashSet + * @param capacity the initial capacity of this set + * @param replace true if this set allows elements to be replaced + */ public KeyedHashSet(int capacity, boolean replace) { elements = new KeyedElement[Math.max(MINIMUM_SIZE, capacity * 2)]; this.replace = replace; this.capacity = capacity; } + /** + * Constructs a new KeyedHashSet and copies to specified KeyedHashSet's contents to the new KeyedHashSet. + * @param original the KeyedHashSet to copy + */ public KeyedHashSet(KeyedHashSet original) { elements = new KeyedElement[original.elements.length]; System.arraycopy(original.elements, 0, elements, 0, original.elements.length); @@ -93,23 +120,50 @@ public class KeyedHashSet { return add(element); } + /** + * Adds the specified list of elements to this set. Some elements may not + * get added if the replace flag is set. + * @param toAdd the list of elements to add to this set. + */ public void addAll(KeyedElement[] toAdd) { for (int i = 0; i < toAdd.length; i++) add(toAdd[i]); } + /** + * Returns true if the specified element exists in this set. + * @param element the requested element + * @return true if the specified element exists in this set; false otherwise. + */ public boolean contains(KeyedElement element) { return get(element) != null; } + /** + * Returns true if an element with the specified key exists in this set. + * @param key the key of the requested element + * @return true if an element with the specified key exists in this set; false otherwise + */ public boolean containsKey(Object key) { return getByKey(key) != null; } + /** + * Returns all elements that exist in this set + * @return all elements that exist in this set + */ public KeyedElement[] elements() { return (KeyedElement[]) elements(new KeyedElement[elementCount]); } + /** + * Copies all elements that exist in this set into the specified array. No size + * checking is done. If the specified array is to small an ArrayIndexOutOfBoundsException + * will be thrown. + * @param result the array to copy the existing elements into. + * @return the specified array. + * @throws ArrayIndexOutOfBoundsException if the specified array is to small. + */ public Object[] elements(Object[] result) { int j = 0; for (int i = 0; i < elements.length; i++) { @@ -144,8 +198,9 @@ public class KeyedHashSet { } /** - * Returns the set element with the given id, or null - * if not found. + * Returns the element with the specified key, or null if not found. + * @param key the requested element's key + * @return the element with the specified key, or null if not found. */ public KeyedElement getByKey(Object key) { if (elementCount == 0) @@ -175,20 +230,22 @@ public class KeyedHashSet { } /** - * Returns the set element with the given id, or null - * if not found. + * Returns the element which compares to the specified element, or null if not found. + * @see KeyedElement#compare(KeyedElement) + * @param otherElement the requested element + * @return the element which compares to the specified element, or null if not found. */ - public KeyedElement get(KeyedElement key) { + public KeyedElement get(KeyedElement otherElement) { if (elementCount == 0) return null; - int hash = hash(key); + int hash = hash(otherElement); // search the last half of the array for (int i = hash; i < elements.length; i++) { KeyedElement element = elements[i]; if (element == null) return null; - if (element.compare(key)) + if (element.compare(otherElement)) return element; } @@ -197,7 +254,7 @@ public class KeyedHashSet { KeyedElement element = elements[i]; if (element == null) return null; - if (element.compare(key)) + if (element.compare(otherElement)) return element; } @@ -205,6 +262,10 @@ public class KeyedHashSet { return null; } + /** + * Returns true if this set is empty + * @return true if this set is empty + */ public boolean isEmpty() { return elementCount == 0; } @@ -212,6 +273,7 @@ public class KeyedHashSet { /** * The element at the given index has been removed so move * elements to keep the set properly hashed. + * @param anIndex the index that has been removed */ protected void rehashTo(int anIndex) { @@ -239,6 +301,11 @@ public class KeyedHashSet { elements[target] = null; } + /** + * Removes the element with the specified key + * @param key the requested element's key + * @return true if an element was removed + */ public boolean removeByKey(Object key) { if (elementCount == 0) return false; @@ -269,6 +336,11 @@ public class KeyedHashSet { return true; } + /** + * Removes the element which compares to the specified element + * @param toRemove the requested element to remove + * @return true if an element was removed + */ public boolean remove(KeyedElement toRemove) { if (elementCount == 0) return false; @@ -307,6 +379,10 @@ public class KeyedHashSet { return Math.abs(key.hashCode()) % elements.length; } + /** + * Removes all of the specified elements from this set + * @param toRemove the requested elements to remove + */ public void removeAll(KeyedElement[] toRemove) { for (int i = 0; i < toRemove.length; i++) remove(toRemove[i]); @@ -316,6 +392,10 @@ public class KeyedHashSet { return elementCount > elements.length * 0.75; } + /** + * Returns the number of elements in this set + * @return the number of elements in this set + */ public int size() { return elementCount; } @@ -337,6 +417,10 @@ public class KeyedHashSet { return result.toString(); } + /** + * Returns the number of collisions this set currently has + * @return the number of collisions this set currently has + */ public int countCollisions() { int result = 0; int lastHash = 0; @@ -361,11 +445,15 @@ public class KeyedHashSet { return result; } + /** + * Returns an iterator of elements in this set + * @return an iterator of elements in this set + */ public Iterator iterator() { - return new KeyedHashSetIterator(); + return new EquinoxSetIterator(); } - class KeyedHashSetIterator implements Iterator { + class EquinoxSetIterator implements Iterator { private int currentIndex = -1; private int found; @@ -391,6 +479,9 @@ public class KeyedHashSet { } } + /** + * Clears all elements from this set + */ public void clear() { elements = new KeyedElement[Math.max(MINIMUM_SIZE, capacity * 2)]; elementCount = 0; diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/AbstractBundle.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/AbstractBundle.java index 8558f16b3..ed980a171 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/AbstractBundle.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/AbstractBundle.java @@ -18,6 +18,7 @@ import java.security.*; import java.util.*; import org.eclipse.osgi.framework.adaptor.*; import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.framework.util.KeyedElement; import org.eclipse.osgi.service.resolver.*; import org.eclipse.osgi.util.NLS; import org.osgi.framework.*; @@ -853,6 +854,11 @@ public abstract class AbstractBundle implements Bundle, Comparable, KeyedElement * Uninstall worker. Assumes the caller has the state change lock. */ protected void uninstallWorkerPrivileged() throws BundleException { + if (Debug.DEBUG) { + BundleWatcher bundleStats = framework.adaptor.getBundleWatcher(); + if (bundleStats != null) + bundleStats.watchBundle(this, BundleWatcher.START_UNINSTALLING); + } boolean unloaded = false; //cache the bundle's headers getHeaders(); @@ -889,6 +895,12 @@ public abstract class AbstractBundle implements Bundle, Comparable, KeyedElement framework.publishFrameworkEvent(FrameworkEvent.ERROR, this, ee); } throw e; + } finally { + if (Debug.DEBUG) { + BundleWatcher bundleStats = framework.adaptor.getBundleWatcher(); + if (bundleStats != null) + bundleStats.watchBundle(this, BundleWatcher.END_UNINSTALLING); + } } } diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java index 7e4e3286e..90934114d 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleHost.java @@ -284,7 +284,7 @@ public class BundleHost extends AbstractBundle { if ((state & (STARTING | ACTIVE)) != 0) { return; } - + boolean shouldStart = false; try { if (state == INSTALLED) { if (!framework.packageAdmin.resolveBundles(new Bundle[] {this})) { @@ -295,15 +295,13 @@ public class BundleHost extends AbstractBundle { if (Debug.DEBUG && Debug.DEBUG_GENERAL) { Debug.println("Bundle: Active sl = " + framework.startLevelManager.getStartLevel() + "; Bundle " + getBundleId() + " sl = " + getStartLevel()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } - - if (getStartLevel() <= framework.startLevelManager.getStartLevel()) { + shouldStart = getStartLevel() <= framework.startLevelManager.getStartLevel(); + if (shouldStart) { //STARTUP TIMING Start here if (Debug.DEBUG) { - if (Debug.MONITOR_ACTIVATION) { - BundleWatcher bundleStats = framework.adaptor.getBundleWatcher(); - if (bundleStats != null) - bundleStats.startActivation(this); - } + BundleWatcher bundleStats = framework.adaptor.getBundleWatcher(); + if (bundleStats != null) + bundleStats.watchBundle(this, BundleWatcher.START_ACTIVATION); if (Debug.DEBUG_BUNDLE_TIME) { start = System.currentTimeMillis(); System.out.println("Starting " + getSymbolicName()); //$NON-NLS-1$ @@ -341,12 +339,10 @@ public class BundleHost extends AbstractBundle { } } } finally { - if (Debug.DEBUG && state == ACTIVE) { - if (Debug.MONITOR_ACTIVATION) { - BundleWatcher bundleStats = framework.adaptor.getBundleWatcher(); - if (bundleStats != null) - bundleStats.endActivation(this); - } + if (Debug.DEBUG && shouldStart) { + BundleWatcher bundleStats = framework.adaptor.getBundleWatcher(); + if (bundleStats != null) + bundleStats.watchBundle(this, BundleWatcher.END_ACTIVATION); if (Debug.DEBUG_BUNDLE_TIME) System.out.println("End starting " + getSymbolicName() + " " + (System.currentTimeMillis() - start)); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -390,7 +386,11 @@ public class BundleHost extends AbstractBundle { if ((state & (STOPPING | RESOLVED | INSTALLED)) != 0) { return; } - + if (Debug.DEBUG) { + BundleWatcher bundleStats = framework.adaptor.getBundleWatcher(); + if (bundleStats != null) + bundleStats.watchBundle(this, BundleWatcher.START_DEACTIVATION); + } state = STOPPING; framework.publishBundleEvent(BundleEvent.STOPPING, this); try { @@ -408,6 +408,11 @@ public class BundleHost extends AbstractBundle { } framework.publishBundleEvent(BundleEvent.STOPPED, this); + if (Debug.DEBUG) { + BundleWatcher bundleStats = framework.adaptor.getBundleWatcher(); + if (bundleStats != null) + bundleStats.watchBundle(this, BundleWatcher.END_DEACTIVATION); + } } } } diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java index acdfc44a4..4bed0e385 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoader.java @@ -18,6 +18,7 @@ import java.security.PrivilegedAction; import java.util.*; import org.eclipse.osgi.framework.adaptor.*; import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.framework.util.KeyedHashSet; import org.eclipse.osgi.service.resolver.*; import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.BundleException; diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoaderProxy.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoaderProxy.java index 66e561f99..0237635e6 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoaderProxy.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleLoaderProxy.java @@ -14,9 +14,9 @@ import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; +import org.eclipse.osgi.framework.util.KeyedHashSet; import org.eclipse.osgi.service.resolver.*; import org.osgi.framework.*; -import org.osgi.framework.Bundle; import org.osgi.service.packageadmin.RequiredBundle; /* diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleRepository.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleRepository.java index 22eaca239..8d83cdc17 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleRepository.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/BundleRepository.java @@ -12,6 +12,7 @@ package org.eclipse.osgi.framework.internal.core; import java.util.*; +import org.eclipse.osgi.framework.util.KeyedHashSet; import org.osgi.framework.Version; /** 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 2fe6625bd..b8cb98405 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 @@ -589,7 +589,7 @@ public class Framework implements EventDispatcher, EventPublisher { * Environment. */ protected boolean verifyExecutionEnvironment(Dictionary manifest) throws BundleException { - if (!Boolean.valueOf(FrameworkProperties.getProperty(Constants.ECLIPSE_EE_INSTALL_VERIFY)).booleanValue()) + if (!Boolean.valueOf(FrameworkProperties.getProperty(Constants.ECLIPSE_EE_INSTALL_VERIFY, Boolean.TRUE.toString())).booleanValue()) //$NON-NLS-1$ return true; String headerValue = (String) manifest.get(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT); /* If no required EE is in the manifest return true */ @@ -837,6 +837,11 @@ public class Framework implements EventDispatcher, EventPublisher { try { BundleData bundledata = storage.begin(); bundle = createAndVerifyBundle(bundledata); + if (Debug.DEBUG) { + BundleWatcher bundleStats = adaptor.getBundleWatcher(); + if (bundleStats != null) + bundleStats.watchBundle(bundle, BundleWatcher.START_INSTALLING); + } try { // Select the native code paths for the bundle; // this is not done by the adaptor because this @@ -872,6 +877,12 @@ public class Framework implements EventDispatcher, EventPublisher { } bundle.close(); throw error; + } finally { + if (Debug.DEBUG) { + BundleWatcher bundleStats = adaptor.getBundleWatcher(); + if (bundleStats != null) + bundleStats.watchBundle(bundle, BundleWatcher.END_INSTALLING); + } } /* bundle has been successfully installed */ bundles.add(bundle); diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/NullPackageSource.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/NullPackageSource.java index e5cd34fed..ea57eefab 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/NullPackageSource.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/NullPackageSource.java @@ -12,6 +12,7 @@ package org.eclipse.osgi.framework.internal.core; import java.net.URL; import java.util.Enumeration; +import org.eclipse.osgi.framework.util.KeyedHashSet; /** * This class is used to optimize finding provided-packages for a bundle. diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PackageSource.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PackageSource.java index 6be9a89da..699c5e96c 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PackageSource.java +++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/PackageSource.java @@ -13,6 +13,7 @@ package org.eclipse.osgi.framework.internal.core; import java.io.IOException; import java.net.URL; import java.util.Enumeration; +import org.eclipse.osgi.framework.util.KeyedElement; public abstract class PackageSource implements KeyedElement { protected String id; 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 index a16093705..5e54721d9 100644 --- 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 @@ -85,7 +85,7 @@ public class Launcher { protected boolean console = false; /** string containing the classname of the adaptor to be used in this framework instance */ - protected String adaptorClassName = "org.eclipse.osgi.framework.internal.defaultadaptor.DefaultAdaptor"; //$NON-NLS-1$ + 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$ diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseAdaptor.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseAdaptor.java new file mode 100644 index 000000000..9107c46dc --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseAdaptor.java @@ -0,0 +1,503 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.baseadaptor; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.Properties; +import org.eclipse.core.runtime.adaptor.LocationManager; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; +import org.eclipse.osgi.baseadaptor.hooks.*; +import org.eclipse.osgi.framework.adaptor.*; +import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.framework.internal.core.*; +import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.log.FrameworkLog; +import org.eclipse.osgi.framework.log.FrameworkLogEntry; +import org.eclipse.osgi.internal.baseadaptor.*; +import org.eclipse.osgi.service.resolver.PlatformAdmin; +import org.eclipse.osgi.service.resolver.State; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.*; + +/** + * A Framework adaptor implementation that allows additional functionality to be + * hooked in. Hooks are configured using {@link HookConfigurator} + * objects. A framework extension may add hook configurators which can be used + * to add hooks to the {@link HookRegistry}. + * @see HookConfigurator + * @see HookRegistry + * @see AdaptorHook + */ +public class BaseAdaptor implements FrameworkAdaptor{ + // System property used to set the parent classloader type (boot is the default) + private static final String PROP_PARENT_CLASSLOADER = "osgi.parentClassloader"; //$NON-NLS-1$ + // A parent classloader type that specifies the application classloader + private static final String PARENT_CLASSLOADER_APP = "app"; //$NON-NLS-1$ + // A parent classloader type that specifies the extension classlaoder + private static final String PARENT_CLASSLOADER_EXT = "ext"; //$NON-NLS-1$ + // A parent classloader type that specifies the boot classlaoder + private static final String PARENT_CLASSLOADER_BOOT = "boot"; //$NON-NLS-1$ + // A parent classloader type that specifies the framework classlaoder + private static final String PARENT_CLASSLOADER_FWK = "fwk"; //$NON-NLS-1$ + // The BundleClassLoader parent to use when creating BundleClassLoaders. + private static ClassLoader bundleClassLoaderParent; + static { + // check property for specified parent + String type = FrameworkProperties.getProperty(BaseAdaptor.PROP_PARENT_CLASSLOADER, BaseAdaptor.PARENT_CLASSLOADER_BOOT); + if (BaseAdaptor.PARENT_CLASSLOADER_FWK.equalsIgnoreCase(type)) + bundleClassLoaderParent = FrameworkAdaptor.class.getClassLoader(); + else if (BaseAdaptor.PARENT_CLASSLOADER_APP.equalsIgnoreCase(type)) + bundleClassLoaderParent = ClassLoader.getSystemClassLoader(); + else if (BaseAdaptor.PARENT_CLASSLOADER_EXT.equalsIgnoreCase(type)) { + ClassLoader appCL = ClassLoader.getSystemClassLoader(); + if (appCL != null) + bundleClassLoaderParent = appCL.getParent(); + } + // default to boot classloader + if (bundleClassLoaderParent == null) + bundleClassLoaderParent = new ParentClassLoader(); + } + + // Empty parent classloader. This is used by default as the BundleClassLoader parent. + private static class ParentClassLoader extends ClassLoader { + protected ParentClassLoader() { + super(null); + } + } + + private EventPublisher eventPublisher; + private ServiceRegistry serviceRegistry; + private boolean stopping; + private HookRegistry hookRegistry; + private FrameworkLog log; + private BundleContext context; + private BaseStorage storage; + private BundleWatcher bundleWatcher; + + /** + * Constructs a BaseAdaptor. + * @param args arguments passed to the adaptor by the framework. + */ + public BaseAdaptor(String[] args) { + if (LocationManager.getConfigurationLocation() == null) + LocationManager.initializeLocations(); + hookRegistry = new HookRegistry(this); + FrameworkLogEntry[] errors = hookRegistry.initialize(); + if (errors.length > 0) + for (int i = 0; i < errors.length; i++) + getFrameworkLog().log(errors[i]); + storage = getStorage(); + // TODO consider passing args to BaseAdaptorHooks + } + + /** + * This method will call all configured adaptor hooks {@link AdaptorHook#initialize(BaseAdaptor)} method. + * @see FrameworkAdaptor#initialize(EventPublisher) + */ + public void initialize(EventPublisher publisher) { + this.eventPublisher = publisher; + serviceRegistry = new ServiceRegistryImpl(); + ((ServiceRegistryImpl) serviceRegistry).initialize(); + // set the adaptor for the adaptor hooks + AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorHooks.length; i++) + adaptorHooks[i].initialize(this); + } + + /** + * @see FrameworkAdaptor#initializeStorage() + */ + public void initializeStorage() throws IOException { + storage.initialize(this); + } + + /** + * @see FrameworkAdaptor#compactStorage() + */ + public void compactStorage() throws IOException { + storage.compact(); + } + + /** + * This method will call all the configured adaptor hook {@link AdaptorHook#addProperties(Properties)} methods. + * @see FrameworkAdaptor#getProperties() + */ + public Properties getProperties() { + Properties props = new Properties(); + String resource = FrameworkProperties.getProperty(Constants.OSGI_PROPERTIES, Constants.DEFAULT_OSGI_PROPERTIES); + try { + InputStream in = null; + File file = new File(resource); + if (file.exists()) + in = new FileInputStream(file); + if (in == null) + in = getClass().getResourceAsStream(resource); + if (in != null) { + try { + props.load(new BufferedInputStream(in)); + } finally { + try { + in.close(); + } catch (IOException ee) { + // nothing to do + } + } + } else { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("Skipping osgi.properties: " + resource); //$NON-NLS-1$ + } + } catch (IOException e) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("Unable to load osgi.properties: " + e.getMessage()); //$NON-NLS-1$ + } + // add the storage properties + storage.addProperties(props); + // add the properties from each adaptor hook + AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorHooks.length; i++) + adaptorHooks[i].addProperties(props); + return props; + } + + /** + * @see FrameworkAdaptor#getInstalledBundles() + */ + public BundleData[] getInstalledBundles() { + return storage.getInstalledBundles(); + } + + /** + * This method will call each configured adaptor hook {@link AdaptorHook#mapLocationToURLConnection(String)} method + * until one returns a non-null value. If none of the adaptor hooks return a non-null value then the + * string is used to construct a new URL object to open a new url connection. + * + * @see FrameworkAdaptor#mapLocationToURLConnection(String) + */ + public URLConnection mapLocationToURLConnection(String location) throws BundleException { + try { + URLConnection result = null; + // try the adaptor hooks first; + AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorHooks.length; i++) { + result = adaptorHooks[i].mapLocationToURLConnection(location); + if (result != null) + return result; + } + // just do the default + return (new URL(location).openConnection()); + } catch (IOException e) { + throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, location), e); + } + } + + /** + * @see FrameworkAdaptor#installBundle(String, URLConnection) + */ + public BundleOperation installBundle(String location, URLConnection source) { + return storage.installBundle(location, source); + } + + /** + * @see FrameworkAdaptor#updateBundle(BundleData, URLConnection) + */ + public BundleOperation updateBundle(BundleData bundledata, URLConnection source) { + return storage.updateBundle((BaseData) bundledata, source); + } + + /** + * @see FrameworkAdaptor#uninstallBundle(BundleData) + */ + public BundleOperation uninstallBundle(BundleData bundledata) { + return storage.uninstallBundle((BaseData) bundledata); + } + + /** + * @see FrameworkAdaptor#getTotalFreeSpace() + */ + public long getTotalFreeSpace() throws IOException { + return storage.getFreeSpace(); + } + + /** + * @see FrameworkAdaptor#getPermissionStorage() + */ + public PermissionStorage getPermissionStorage() throws IOException { + return storage.getPermissionStorage(); + } + + /** + * @see FrameworkAdaptor#getServiceRegistry() + */ + public ServiceRegistry getServiceRegistry() { + return serviceRegistry; + } + + /** + * This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStart(BundleContext)} methods. + * @see FrameworkAdaptor#frameworkStart(BundleContext) + */ + public void frameworkStart(BundleContext fwContext) throws BundleException { + this.context = fwContext; + stopping = false; + BundleResourceHandler.setContext(fwContext); + // always start the storage first + storage.frameworkStart(fwContext); + AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorHooks.length; i++) + adaptorHooks[i].frameworkStart(fwContext); + } + + /** + * This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStop(BundleContext)} methods. + * @see FrameworkAdaptor#frameworkStop(BundleContext) + */ + public void frameworkStop(BundleContext fwContext) throws BundleException { + // first inform all configured adaptor hooks + AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorHooks.length; i++) + adaptorHooks[i].frameworkStop(fwContext); + // stop the storage last + storage.frameworkStop(fwContext); + fwContext = null; + } + + /** + * This method calls all the configured adaptor hook {@link AdaptorHook#frameworkStopping(BundleContext)} methods. + * @see FrameworkAdaptor#frameworkStopping(BundleContext) + */ + public void frameworkStopping(BundleContext fwContext) { + stopping = true; + // always tell storage of stopping first + storage.frameworkStopping(fwContext); + // inform all configured adaptor hooks last + AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorHooks.length; i++) + adaptorHooks[i].frameworkStopping(fwContext); + } + + /** + * @see FrameworkAdaptor#getInitialBundleStartLevel() + */ + public int getInitialBundleStartLevel() { + return storage.getInitialBundleStartLevel(); + } + + /** + * @see FrameworkAdaptor#setInitialBundleStartLevel(int) + */ + public void setInitialBundleStartLevel(int value) { + storage.setInitialBundleStartLevel(value); + } + + /** + * This method calls all configured adaptor hook {@link AdaptorHook#createFrameworkLog()} methods + * until the first one returns a non-null value. If none of the adaptor hooks return a non-null + * value then a framework log implementation which does nothing is returned. + * @see FrameworkAdaptor#getFrameworkLog() + */ + public FrameworkLog getFrameworkLog() { + if (log != null) + return log; + AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorHooks.length; i++) { + log = adaptorHooks[i].createFrameworkLog(); + if (log != null) + return log; + } + log = new FrameworkLog() { + public void log(FrameworkEvent frameworkEvent) { + log(new FrameworkLogEntry(frameworkEvent.getBundle().getSymbolicName() == null ? frameworkEvent.getBundle().getLocation() : frameworkEvent.getBundle().getSymbolicName(), FrameworkLogEntry.ERROR, 0, "FrameworkEvent.ERROR", 0, frameworkEvent.getThrowable(), null)); //$NON-NLS-1$ + } + + public void log(FrameworkLogEntry logEntry) { + System.err.print(logEntry.getEntry() + " "); //$NON-NLS-1$ + System.err.println(logEntry.getMessage()); + if (logEntry.getThrowable() != null) + logEntry.getThrowable().printStackTrace(System.err); + } + + public void setWriter(Writer newWriter, boolean append) { + // do nothing + } + + public void setFile(File newFile, boolean append) throws IOException { + // do nothing + } + + public File getFile() { + // do nothing + return null; + } + + public void setConsoleLog(boolean consoleLog) { + // do nothing + } + + public void close() { + // do nothing + } + }; + return log; + } + + /** + * @see FrameworkAdaptor#createSystemBundleData() + */ + public BundleData createSystemBundleData() throws BundleException { + return new SystemBundleData(this); + } + + /** + * @see FrameworkAdaptor#getBundleWatcher() + */ + public BundleWatcher getBundleWatcher() { + if (bundleWatcher != null) + return bundleWatcher; + final BundleWatcher[] watchers = hookRegistry.getWatchers(); + if (watchers.length == 0) + return null; + bundleWatcher = new BundleWatcher() { + public void watchBundle(Bundle bundle, int type) { + for (int i = 0; i < watchers.length; i++) + watchers[i].watchBundle(bundle, type); + } + }; + return bundleWatcher; + } + + /** + * @see FrameworkAdaptor#getPlatformAdmin() + */ + public PlatformAdmin getPlatformAdmin() { + return storage.getStateManager(); + } + + /** + * @see FrameworkAdaptor#getState() + */ + public State getState() { + return storage.getStateManager().getSystemState(); + } + + /** + * This method calls all the configured classloading hooks {@link ClassLoadingHook#getBundleClassLoaderParent()} methods + * until one returns a non-null value. + * @see FrameworkAdaptor#getBundleClassLoaderParent() + */ + public ClassLoader getBundleClassLoaderParent() { + // ask the configured adaptor hooks first + ClassLoader result = null; + ClassLoadingHook[] cpManagerHooks = getHookRegistry().getClassLoadingHooks(); + for (int i = 0; i < cpManagerHooks.length; i++) { + result = cpManagerHooks[i].getBundleClassLoaderParent(); + if (result != null) + return result; + } + // none of the configured adaptor hooks gave use a parent loader; use the default + return bundleClassLoaderParent; + } + + /** + * This method calls all the configured adaptor hooks {@link AdaptorHook#handleRuntimeError(Throwable)} methods. + * @see FrameworkAdaptor#handleRuntimeError(Throwable) + */ + public void handleRuntimeError(Throwable error) { + AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorHooks.length; i++) + adaptorHooks[i].handleRuntimeError(error); + } + + /** + * This method calls all the configured adaptor hooks {@link AdaptorHook#matchDNChain(String, String[])} methods + * until one returns a true value. + * @see FrameworkAdaptor#matchDNChain(String, String[]) + */ + public boolean matchDNChain(String pattern, String[] dnChain) { + AdaptorHook[] adaptorHooks = getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorHooks.length; i++) + if (adaptorHooks[i].matchDNChain(pattern, dnChain)) + return true; + return false; + } + + /** + * Returns true if the {@link #frameworkStopping(BundleContext)} method has been called + * @return true if the framework is stopping + */ + public boolean isStopping() { + return stopping; + } + + /** + * Returns the event publisher for this BaseAdaptor + * @return the event publisher for this BaseAdaptor + */ + public EventPublisher getEventPublisher() { + return eventPublisher; + } + + /** + * Returns the <code>HookRegistry</code> object for this adaptor. + * @return the <code>HookRegistry</code> object for this adaptor. + */ + public HookRegistry getHookRegistry() { + return hookRegistry; + } + + /** + * Returns the system bundle's context + * @return the system bundle's context + */ + public BundleContext getContext() { + return context; + } + + /** + * Creates a bundle file object for the given content and base data. + * This method must delegate to each configured bundle file factory + * {@link BundleFileFactoryHook#createBundleFile(Object, BaseData, boolean)} method until one + * factory returns a non-null value. If no bundle file factory returns a non-null value + * then the the default behavior will be performed. <p> + * If the specified content is <code>null</code> then the base content of the specified + * bundledata must be found before calling any bundle file factories. + * @param content The object which contains the content of a bundle file. A value of + * <code>null</code> indicates that the storage must find the base content for the + * specified BaseData. + * @param data The BaseData associated with the content + * @return a BundleFile object. + * @throws IOException if an error occured while creating the BundleFile + */ + public BundleFile createBundleFile(Object content, BaseData data) throws IOException { + return storage.createBundleFile(content, data); + } + + /** + * Returns true if the persistent storage is read-only + * @return true if the persistent storage is read-only + */ + public boolean isReadOnly() { + return storage.isReadOnly(); + } + + /* + * This is an experimental method to allow adaptors to replace the storage implementation by + * extending BaseAdaptor and overriding this method. This method is experimental. + * @return a base storage object. + */ + protected BaseStorage getStorage() { + if (storage == null) + storage = BaseStorage.getInstance(); + return storage; + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java new file mode 100644 index 000000000..5e21c088a --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/BaseData.java @@ -0,0 +1,442 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.baseadaptor; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; +import org.eclipse.osgi.baseadaptor.hooks.*; +import org.eclipse.osgi.baseadaptor.loader.BaseClassLoader; +import org.eclipse.osgi.framework.adaptor.*; +import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.internal.protocol.bundleentry.Handler; +import org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader; +import org.eclipse.osgi.util.ManifestElement; +import org.osgi.framework.*; + +/** + * The BundleData implementation used by the BaseAdaptor. + * @see BaseAdaptor + * @see BundleData + * @see StorageHook + * @see ClassLoadingHook + */ +public class BaseData implements BundleData { + private long id; + private BaseAdaptor adaptor; + private Bundle bundle; + private int startLevel = -1; + private int status = 0; + private StorageHook[] storageHooks; + private String location; + private long lastModified; + protected BundleFile bundleFile; + private boolean dirty = false; + protected Dictionary manifest; + + ///////////////////// Begin values from Manifest ///////////////////// + private String symbolicName; + private Version version; + private String activator; + private String classpath; + private String executionEnvironment; + private String dynamicImports; + private int type; + + ///////////////////// End values from Manifest ///////////////////// + + /** + * Constructs a new BaseData with the specified id for the specified adaptor + * @param id the id of the BaseData + * @param adaptor the adaptor of the BaseData + */ + public BaseData(long id, BaseAdaptor adaptor) { + this.id = id; + this.adaptor = adaptor; + } + + /** + * This method calls all the configured class loading hooks {@link ClassLoadingHook#createClassLoader(ClassLoader, ClassLoaderDelegate, BundleProtectionDomain, BaseData, String[])} + * methods until on returns a non-null value. If none of the class loading hooks returns a non-null value + * then the default classloader implementation is used. <p> + * After the classloader is created all configured class loading hooks + * {@link ClassLoadingHook#initializedClassLoader(BaseClassLoader, BaseData)} methods are called. + * @see BundleData#createClassLoader(ClassLoaderDelegate, BundleProtectionDomain, String[]) + */ + public BundleClassLoader createClassLoader(ClassLoaderDelegate delegate, BundleProtectionDomain domain, String[] bundleclasspath) { + ClassLoadingHook[] hooks = adaptor.getHookRegistry().getClassLoadingHooks(); + ClassLoader parent = adaptor.getBundleClassLoaderParent(); + BaseClassLoader cl = null; + for (int i = 0; i < hooks.length && cl == null; i++) + cl = hooks[i].createClassLoader(parent, delegate, domain, this, bundleclasspath); + if (cl == null) + cl = new DefaultClassLoader(parent, delegate, domain, this, bundleclasspath); + for (int i = 0; i < hooks.length; i++) + hooks[i].initializedClassLoader(cl, this); + return cl; + } + + public final URL getEntry(String path) { + BundleEntry entry = getBundleFile().getEntry(path); + if (entry == null) + return null; + if (path.length() == 0 || path.charAt(0) != '/') + path = path = '/' + path; + try { + //use the constant string for the protocol to prevent duplication + return new URL(Constants.OSGI_ENTRY_URL_PROTOCOL, Long.toString(id), 0, path, new Handler(entry)); + } catch (MalformedURLException e) { + return null; + } + } + + public final Enumeration getEntryPaths(String path) { + return getBundleFile().getEntryPaths(path); + } + + /** + * This method calls each configured classloading hook {@link ClassLoadingHook#findLibrary(BaseData, String)} method + * until the first one returns a non-null value. + * @see BundleData#findLibrary(String) + */ + public String findLibrary(String libname) { + ClassLoadingHook[] hooks = adaptor.getHookRegistry().getClassLoadingHooks(); + String result = null; + for (int i = 0; i < hooks.length; i++) { + result = hooks[i].findLibrary(this, libname); + if (result != null) + return result; + } + return result; + } + + public void installNativeCode(String[] nativepaths) throws BundleException { + adaptor.getStorage().installNativeCode(this, nativepaths); + } + + public File getDataFile(String path) { + return adaptor.getStorage().getDataFile(this, path); + } + + public Dictionary getManifest() throws BundleException { + if (manifest == null) + manifest = adaptor.getStorage().loadManifest(this); + return manifest; + } + + public long getBundleID() { + return id; + } + + public final String getLocation() { + return location; + } + + /** + * Sets the location of this bundledata + * @param location the location of this bundledata + */ + public final void setLocation(String location) { + this.location = location; + } + + public final long getLastModified() { + return lastModified; + } + + /** + * Sets the last modified time stamp of this bundledata + * @param lastModified the last modified time stamp of this bundledata + */ + public final void setLastModified(long lastModified) { + this.lastModified = lastModified; + } + + public void close() throws IOException { + if (bundleFile != null) + getBundleFile().close(); // only close the bundleFile if it already exists. + } + + public void open() throws IOException { + getBundleFile().open(); + } + + public final void setBundle(Bundle bundle) { + this.bundle = bundle; + } + + /** + * Returns the bundle object of this BaseData + * @return the bundle object of this BaseData + */ + public final Bundle getBundle() { + return bundle; + } + + public int getStartLevel() { + return startLevel; + } + + public int getStatus() { + return status; + } + + /** + * This method calls each configured storage hook {@link StorageHook#forgetStartLevelChange(int)} method. + * If one returns true then this bundledata is not marked dirty. + * @see BundleData#setStartLevel(int) + */ + public void setStartLevel(int value) { + startLevel = setPersistentData(value, true, startLevel); + } + + /** + * This method calls each configured storage hook {@link StorageHook#forgetStatusChange(int)} method. + * If one returns true then this bundledata is not marked dirty. + * @see BundleData#setStatus(int) + */ + public void setStatus(int value) { + status = setPersistentData(value, false, status); + } + + private int setPersistentData(int value, boolean isStartLevel, int orig) { + StorageHook[] hooks = getStorageHooks(); + for (int i = 0; i < hooks.length; i++) + if (isStartLevel) { + if (hooks[i].forgetStartLevelChange(value)) + return value; + } else { + if (hooks[i].forgetStatusChange(value)) + return value; + } + if (value != orig) + dirty = true; + return value; + } + + public void save() throws IOException { + adaptor.getStorage().save(this); + } + + /** + * Returns true if this bundledata is dirty + * @return true if this bundledata is dirty + */ + public boolean isDirty() { + return dirty; + } + + /** + * Sets the dirty flag for this BaseData + * @param dirty the dirty flag + */ + public void setDirty(boolean dirty) { + this.dirty = dirty; + } + + public final String getSymbolicName() { + return symbolicName; + } + + /** + * Sets the symbolic name of this BaseData + * @param symbolicName the symbolic name + */ + public final void setSymbolicName(String symbolicName) { + this.symbolicName = symbolicName; + } + + public final Version getVersion() { + return version; + } + + /** + * Sets the version of this BaseData + * @param version the version + */ + public final void setVersion(Version version) { + this.version = version; + } + + public final int getType() { + return type; + } + + /** + * Sets the type of this BaseData + * @param type the type + */ + public final void setType(int type) { + this.type = type; + } + + public final String[] getClassPath() throws BundleException { + ManifestElement[] classpathElements = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, classpath); + return getClassPath(classpathElements); + } + + // TODO make classpath a String[] instead of saving a comma separated string. + public String getClassPathString() { + return classpath; + } + + //TODO make classpath a String[] instead of saving a comma separated string. + public void setClassPathString(String classpath) { + this.classpath = classpath; + } + + public final String getActivator() { + return activator; + } + + /** + * Sets the activator of this BaseData + * @param activator the activator + */ + public final void setActivator(String activator) { + this.activator = activator; + } + + public final String getExecutionEnvironment() { + return executionEnvironment; + } + + /** + * Sets the execution environment of this BaseData + * @param executionEnvironment the execution environment + */ + public void setExecutionEnvironment(String executionEnvironment) { + this.executionEnvironment = executionEnvironment; + } + + public final String getDynamicImports() { + return dynamicImports; + } + + /** + * Sets the dynamic imports of this BaseData + * @param dynamicImports the dynamic imports + */ + public void setDynamicImports(String dynamicImports) { + this.dynamicImports = dynamicImports; + } + + /** + * This method calls each configured storage hook {@link StorageHook#matchDNChain(String)} method + * until one returns true. If no configured storage hook returns true then false is returned. + * @see BundleData#matchDNChain(String) + */ + public final boolean matchDNChain(String pattern) { + StorageHook[] hooks = getStorageHooks(); + for (int i = 0; i < hooks.length; i++) + if (hooks[i].matchDNChain(pattern)) + return true; + return false; + } + + /** + * Returns the adaptor for this BaseData + * @return the adaptor + */ + public final BaseAdaptor getAdaptor() { + return adaptor; + } + + /** + * Returns the BundleFile for this BaseData. The first time this method is called the + * configured storage {@link BaseAdaptor#createBundleFile(Object, BaseData)} method is called. + * @return the BundleFile + * @throws IllegalArgumentException + */ + public synchronized BundleFile getBundleFile() throws IllegalArgumentException { + if (bundleFile == null) + try { + bundleFile = adaptor.createBundleFile(null, this); + } catch (IOException e) { + throw new IllegalArgumentException(e.getMessage()); + } + return bundleFile; + } + + private static String[] getClassPath(ManifestElement[] classpath) { + if (classpath == null) { + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println(" no classpath"); //$NON-NLS-1$ + /* create default BundleClassPath */ + return new String[] {"."}; //$NON-NLS-1$ + } + + ArrayList result = new ArrayList(classpath.length); + for (int i = 0; i < classpath.length; i++) { + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println(" found classpath entry " + classpath[i].getValueComponents()); //$NON-NLS-1$ + String[] paths = classpath[i].getValueComponents(); + for (int j = 0; j < paths.length; j++) { + result.add(paths[j]); + } + } + + return (String[]) result.toArray(new String[result.size()]); + } + + /** + * Returns the storage hook which is keyed by the specified key + * @param key the key of the storage hook to get + * @return the storage hook which is keyed by the specified key + */ + public StorageHook getStorageHook(String key) { + if (storageHooks == null) + return null; + for (int i = 0; i < storageHooks.length; i++) + if (storageHooks[i].getKey().equals(key)) + return storageHooks[i]; + return null; + } + + /** + * Sets the instance storage hooks for this base data. This is method + * may only be called once for the lifetime of the base data. Once set, + * the list of storage hooks remains constant. + * @param storageHooks the storage hook to add + */ + public void setStorageHooks(StorageHook[] storageHooks) { + if (this.storageHooks != null) + return; // only allow this to be set once. + this.storageHooks = storageHooks; + } + + /** + * Returns all the storage hooks associated with this BaseData + * @return all the storage hooks associated with this BaseData + */ + public StorageHook[] getStorageHooks() { + return storageHooks == null ? new StorageHook[0] : storageHooks; + } + + /** + * Gets called by BundleFile during {@link BundleFile#getFile(String, boolean)}. This method + * will allocate a File object where content of the specified path may be + * stored for the current generation of the base data. The returned File object may + * not exist if the content has not previously be stored. + * @param path the path to the content to extract from the base data + * @return a file object where content of the specified path may be stored. + */ + public File getExtractFile(String path) { + return adaptor.getStorage().getExtractFile(this, path); + } + +} diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/KeyedElement.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/HookConfigurator.java index c92db70e9..453574ceb 100644 --- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/KeyedElement.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/HookConfigurator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2004 IBM Corporation and others. + * Copyright (c) 2005 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 @@ -8,12 +8,17 @@ * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ -package org.eclipse.osgi.framework.internal.core; -public interface KeyedElement { - public int getKeyHashCode(); +package org.eclipse.osgi.baseadaptor; - public boolean compare(KeyedElement other); - - public Object getKey(); +/** + * A hook configurator is used to add hooks to the hook registry. + * @see HookRegistry + */ +public interface HookConfigurator { + /** + * Adds hooks to the specified hook registry. + * @param hookRegistry the hook registry used to add hooks + */ + public void addHooks(HookRegistry hookRegistry); } diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/HookRegistry.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/HookRegistry.java new file mode 100644 index 000000000..bc3f7cdf4 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/HookRegistry.java @@ -0,0 +1,282 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.baseadaptor; + +import java.io.IOException; +import java.net.URL; +import java.util.*; +import org.eclipse.osgi.baseadaptor.hooks.*; +import org.eclipse.osgi.framework.adaptor.BundleWatcher; +import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; +import org.eclipse.osgi.framework.internal.core.FrameworkProperties; +import org.eclipse.osgi.framework.log.FrameworkLogEntry; +import org.eclipse.osgi.util.ManifestElement; + +/** + * The hook registry is used to store all the hooks which are + * configured by the hook configurators. + * @see HookConfigurator + */ +public final class HookRegistry { + /** + * The hook configurators properties file ("hookconfigurators.properties") <p> + * A framework extension may supply a hook configurators properties file to specify a + * list of hook configurators. + * @see #HOOK_CONFIGURATORS + */ + public static final String HOOK_CONFIGURATORS_FILE = "hookconfigurators.properties"; //$NON-NLS-1$ + + /** + * The hook configurators property key ("hookconfigurators.properties") used in + * a hook configurators properties file to specify a comma separated list of fully + * qualified hook configurator classes. + */ + public static final String HOOK_CONFIGURATORS = "hook.configurators"; //$NON-NLS-1$ + + /** + * A system property ("osgi.hook.configurators.include") used to add additional + * hook configurators. This is helpful for configuring optional hook configurators. + */ + public static final String PROP_HOOK_CONFIGURATORS_INCLUDE = "osgi.hook.configurators.include"; //$NON-NLS-1$ + + /** + * A system property ("osgi.hook.configurators.exclude") used to exclude + * any hook configurators. This is helpful for disabling hook + * configurators that is specified in hook configurator properties files. + */ + public static final String PROP_HOOK_CONFIGURATORS_EXCLUDE = "osgi.hook.configurators.exclude"; //$NON-NLS-1$ + + /** + * A system property ("osgi.hook.configurators") used to specify the list + * of hook configurators. If this property is set then the list of configurators + * specified will be the only configurators used. + */ + public static final String PROP_HOOK_CONFIGURATORS = "osgi.hook.configurators"; //$NON-NLS-1$ + + private BaseAdaptor adaptor; + private boolean readonly = false; + private AdaptorHook[] adaptorHooks = new AdaptorHook[0]; + private BundleWatcher[] watchers = new BundleWatcher[0]; + private ClassLoadingHook[] classLoadingHooks = new ClassLoadingHook[0]; + private ClassLoadingStatsHook[] classLoadingStatsHooks = new ClassLoadingStatsHook[0]; + private StorageHook[] storageHooks = new StorageHook[0]; + private BundleFileFactoryHook[] bundleFileFactoryHooks = new BundleFileFactoryHook[0]; + + public HookRegistry(BaseAdaptor adaptor) { + this.adaptor = adaptor; + } + + /** + * Initializes the hook configurators. The following steps are used to initialize the hook configurators. <p> + * 1. Get a list of hook configurators from all hook configurators properties files on the classpath, + * add this list to the overall list of hook configurators, remove duplicates. <p> + * 2. Get a list of hook configurators from the ("osgi.hook.configurators.include") system property + * and add this list to the overall list of hook configurators, remove duplicates. <p> + * 3. Get a list of hook configurators from the ("osgi.hook.configurators.exclude") system property + * and remove this list from the overall list of hook configurators. <p> + * 4. Load each hook configurator class, create a new instance, then call the {@link HookConfigurator#addHooks(HookRegistry)} method <p> + * 5. Set this HookRegistry object to read only to prevent any other hooks from being added. <p> + * @return an array of error log entries that occurred while initializing the hooks + */ + public FrameworkLogEntry[] initialize() { + ArrayList configurators = new ArrayList(5); + ArrayList errors = new ArrayList(0); // optimistic that no errors will occur + mergeFileHookConfigurators(configurators, errors); + mergePropertyHookConfigurators(configurators); + loadConfigurators(configurators, errors); + // set to read-only + readonly = true; + return (FrameworkLogEntry[]) errors.toArray(new FrameworkLogEntry[errors.size()]); + } + + private void mergeFileHookConfigurators(ArrayList configuratorList, ArrayList errors) { + ClassLoader cl = getClass().getClassLoader(); + // get all hook configurators files in your classloader delegation + Enumeration hookConfigurators; + try { + hookConfigurators = cl != null ? cl.getResources(HookRegistry.HOOK_CONFIGURATORS_FILE) : ClassLoader.getSystemResources(HookRegistry.HOOK_CONFIGURATORS_FILE); + } catch (IOException e) { + errors.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, "getResources error on " + HookRegistry.HOOK_CONFIGURATORS_FILE, 0, e, null)); //$NON-NLS-1$ + return; + } + while (hookConfigurators.hasMoreElements()) { + URL url = (URL) hookConfigurators.nextElement(); + try { + // check each file for a hook.configurators property + Properties configuratorProps = new Properties(); + configuratorProps.load(url.openStream()); + String hooksValue = configuratorProps.getProperty(HOOK_CONFIGURATORS); + if (hooksValue == null) + continue; + String[] configurators = ManifestElement.getArrayFromList(hooksValue, ","); //$NON-NLS-1$ + for (int i = 0; i < configurators.length; i++) + if (!configuratorList.contains(configurators[i])) + configuratorList.add(configurators[i]); + } catch (IOException e) { + errors.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, "error loading: " + url.toExternalForm(), 0, e, null)); //$NON-NLS-1$ + // ignore and continue to next URL + } + } + } + + private void mergePropertyHookConfigurators(ArrayList configuratorList) { + // see if there is a configurators list + String[] configurators = ManifestElement.getArrayFromList(FrameworkProperties.getProperty(HookRegistry.PROP_HOOK_CONFIGURATORS), ","); //$NON-NLS-1$ + if (configurators.length > 0) { + configuratorList.clear(); // clear the list, we are only going to use the configurators from the list + for (int i = 0; i < configurators.length; i++) + if (!configuratorList.contains(configurators[i])) + configuratorList.add(configurators[i]); + return; // don't do anything else + } + // Make sure the configurators from the include property are in the list + String[] includeConfigurators = ManifestElement.getArrayFromList(FrameworkProperties.getProperty(HookRegistry.PROP_HOOK_CONFIGURATORS_INCLUDE), ","); //$NON-NLS-1$ + for (int i = 0; i < includeConfigurators.length; i++) + if (!configuratorList.contains(includeConfigurators[i])) + configuratorList.add(includeConfigurators[i]); + // Make sure the configurators from the exclude property are no in the list + String[] excludeHooks = ManifestElement.getArrayFromList(FrameworkProperties.getProperty(HookRegistry.PROP_HOOK_CONFIGURATORS_EXCLUDE), ","); //$NON-NLS-1$ + for (int i = 0; i < excludeHooks.length; i++) + configuratorList.remove(excludeHooks[i]); + } + + private void loadConfigurators(ArrayList configurators, ArrayList errors) { + for (Iterator iHooks = configurators.iterator(); iHooks.hasNext();) { + String hookName = (String) iHooks.next(); + try { + Class clazz = Class.forName(hookName); + HookConfigurator configurator = (HookConfigurator) clazz.newInstance(); + configurator.addHooks(this); + } catch (Throwable t) { + // We expect the follow exeptions may happen; but we need to catch all here + // ClassNotFoundException + // IllegalAccessException + // InstantiationException + // ClassCastException + errors.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, "error loading hook: " + hookName, 0, t, null)); //$NON-NLS-1$ + } + } + } + + /** + * Returns the list of configured adaptor hooks. + * @return the list of configured adaptor hooks. + */ + public AdaptorHook[] getAdaptorHooks() { + return adaptorHooks; + } + + /** + * Returns the list of configured bundle watchers. + * @return the list of configured bundle watchers. + */ + public BundleWatcher[] getWatchers() { + return watchers; + } + + /** + * Returns the list of configured class loading hooks. + * @return the list of configured class loading hooks. + */ + public ClassLoadingHook[] getClassLoadingHooks() { + return classLoadingHooks; + } + + /** + * Returns the list of configured class loading stats hooks. + * @return the list of configured class loading stats hooks. + */ + public ClassLoadingStatsHook[] getClassLoadingStatsHooks() { + return classLoadingStatsHooks; + } + + /** + * Returns the list of configured storage hooks. + * @return the list of configured storage hooks. + */ + public StorageHook[] getStorageHooks() { + return storageHooks; + } + + /** + * Returns the list of configured bundle file factories. + * @return the list of configured bundle file factories. + */ + public BundleFileFactoryHook[] getBundleFileFactoryHooks() { + return bundleFileFactoryHooks; + } + + /** + * Adds a adaptor hook to this hook registry. + * @param adaptorHook an adaptor hook object. + */ + public void addAdaptorHook(AdaptorHook adaptorHook) { + adaptorHooks = (AdaptorHook[]) add(adaptorHook, adaptorHooks, new AdaptorHook[adaptorHooks.length + 1]); + } + + /** + * Adds a bundle watcher to this hook registry. + * @param watcher a bundle watcher object. + */ + public void addWatcher(BundleWatcher watcher) { + watchers = (BundleWatcher[]) add(watcher, watchers, new BundleWatcher[watchers.length + 1]); + } + + /** + * Adds a class loading hook to this hook registry. + * @param classLoadingHook a class loading hook object. + */ + public void addClassLoadingHook(ClassLoadingHook classLoadingHook) { + classLoadingHooks = (ClassLoadingHook[]) add(classLoadingHook, classLoadingHooks, new ClassLoadingHook[classLoadingHooks.length + 1]); + } + + /** + * Adds a class loading stats hook to this hook registry. + * @param classLoadingStatsHook a class loading hook object. + */ + public void addClassLoadingStatsHook(ClassLoadingStatsHook classLoadingStatsHook) { + classLoadingStatsHooks = (ClassLoadingStatsHook[]) add(classLoadingStatsHook, classLoadingStatsHooks, new ClassLoadingStatsHook[classLoadingStatsHooks.length + 1]); + } + + /** + * Adds a storage hook to this hook registry. + * @param storageHook a storage hook object. + */ + public void addStorageHook(StorageHook storageHook) { + storageHooks = (StorageHook[]) add(storageHook, storageHooks, new StorageHook[storageHooks.length + 1]); + } + + /** + * Adds a bundle file factory to this hook registry. + * @param factory an bundle file factory object. + */ + public void addBundleFileFactoryHook(BundleFileFactoryHook factory) { + bundleFileFactoryHooks = (BundleFileFactoryHook[]) add(factory, bundleFileFactoryHooks, new BundleFileFactoryHook[bundleFileFactoryHooks.length + 1]); + } + + private Object[] add(Object newValue, Object[] oldValues, Object[] newValues) { + if (readonly) + throw new IllegalStateException("Cannot add hooks dynamically."); + if (oldValues.length > 0) + System.arraycopy(oldValues, 0, newValues, 0, oldValues.length); + newValues[oldValues.length] = newValue; + return newValues; + } + + /** + * Returns the base adaptor associated with this hook registry. + * @return the base adaptor associated with this hook registry. + */ + public BaseAdaptor getAdaptor() { + return adaptor; + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleEntry.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleEntry.java new file mode 100644 index 000000000..b3e8007bc --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleEntry.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2004, 2005 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.baseadaptor.bundlefile; + +import java.io.*; +import java.net.URL; + +/** + * A BundleEntry represents one entry of a BundleFile. + * <p> + * Clients may extend this class. + * </p> + * @since 3.1 + */ +public abstract class BundleEntry { + /** + * Return an InputStream for the entry. + * + * @return InputStream for the entry. + * @throws java.io.IOException If an error occurs reading the bundle. + */ + public abstract InputStream getInputStream() throws IOException; + + /** + * Return the size of the entry (uncompressed). + * + * @return size of entry. + */ + public abstract long getSize(); + + /** + * Return the name of the entry. + * + * @return name of entry. + */ + public abstract String getName(); + + /** + * Get the modification time for this BundleEntry. + * <p>If the modification time has not been set, + * this method will return <tt>-1</tt>. + * + * @return last modification time. + */ + public abstract long getTime(); + + /** + * Get a URL to the bundle entry that uses a common protocol (i.e. file: + * jar: or http: etc.). + * @return a URL to the bundle entry that uses a common protocol + */ + public abstract URL getLocalURL(); + + /** + * Get a URL to the content of the bundle entry that uses the file: protocol. + * The content of the bundle entry may be downloaded or extracted to the local + * file system in order to create a file: URL. + * @return a URL to the content of the bundle entry that uses the file: protocol + */ + public abstract URL getFileURL(); + + /** + * Return the name of this BundleEntry by calling getName(). + * + * @return String representation of this BundleEntry. + */ + public String toString() { + return (getName()); + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java new file mode 100644 index 000000000..cb07047e8 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/BundleFile.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2004, 2005 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.baseadaptor.bundlefile; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; +import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.internal.core.FrameworkProperties; +import org.eclipse.osgi.framework.internal.protocol.bundleresource.Handler; +import org.eclipse.osgi.framework.util.SecureAction; +import org.eclipse.osgi.util.ManifestElement; + +/** + * The BundleFile API is used by Adaptors to read resources out of an + * installed Bundle in the Framework. + * <p> + * Clients may extend this class. + * </p> + * @since 3.1 + */ +abstract public class BundleFile { + protected static final String PROP_SETPERMS_CMD = "osgi.filepermissions.command"; //$NON-NLS-1$ + static final SecureAction secureAction = new SecureAction(); + /** + * The File object for this BundleFile. + */ + protected File basefile; + private int mruIndex = -1; + + /** + * Default constructor + * + */ + public BundleFile() { + // do nothing + } + + /** + * BundleFile constructor + * @param basefile The File object where this BundleFile is + * persistently stored. + */ + public BundleFile(File basefile) { + this.basefile = basefile; + } + + /** + * Returns a File for the bundle entry specified by the path. + * If required the content of the bundle entry is extracted into a file + * on the file system. + * @param path The path to the entry to locate a File for. + * @param nativeCode true if the path is native code. + * @return A File object to access the contents of the bundle entry. + */ + abstract public File getFile(String path, boolean nativeCode); + + /** + * Locates a file name in this bundle and returns a BundleEntry object + * + * @param path path of the entry to locate in the bundle + * @return BundleEntry object or null if the file name + * does not exist in the bundle + */ + abstract public BundleEntry getEntry(String path); + + /** + * Allows to access the entries of the bundle. + * Since the bundle content is usually a jar, this + * allows to access the jar contents. + * + * GetEntryPaths allows to enumerate the content of "path". + * If path is a directory, it is equivalent to listing the directory + * contents. The returned names are either files or directories + * themselves. If a returned name is a directory, it finishes with a + * slash. If a returned name is a file, it does not finish with a slash. + * @param path path of the entry to locate in the bundle + * @return an Enumeration of Strings that indicate the paths found or + * null if the path does not exist. + */ + abstract public Enumeration getEntryPaths(String path); + + /** + * Closes the BundleFile. + * @throws IOException if any error occurs. + */ + abstract public void close() throws IOException; + + /** + * Opens the BundleFiles. + * @throws IOException if any error occurs. + */ + abstract public void open() throws IOException; + + /** + * Determines if any BundleEntries exist in the given directory path. + * @param dir The directory path to check existence of. + * @return true if the BundleFile contains entries under the given directory path; + * false otherwise. + */ + abstract public boolean containsDir(String dir); + + /** + * Returns a URL to access the contents of the entry specified by the path + * @param path the path to the resource + * @param hostBundleID the host bundle ID + * @return a URL to access the contents of the entry specified by the path + */ + public URL getResourceURL(String path, long hostBundleID) { + return getResourceURL(path, hostBundleID, 0); + } + + /** + * Returns a URL to access the contents of the entry specified by the path + * @param path the path to the resource + * @param hostBundleID the host bundle ID + * @param index the resource index + * @return a URL to access the contents of the entry specified by the path + */ + public URL getResourceURL(String path, long hostBundleID, int index) { + BundleEntry bundleEntry = getEntry(path); + if (bundleEntry == null) + return null; + if (path.length() == 0 || path.charAt(0) != '/') + path = '/' + path; + try { + //use the constant string for the protocol to prevent duplication + return secureAction.getURL(Constants.OSGI_RESOURCE_URL_PROTOCOL, Long.toString(hostBundleID), index, path, new Handler(bundleEntry)); + } catch (MalformedURLException e) { + return null; + } + } + + /** + * Returns the base file for this BundleFile + * @return the base file for this BundleFile + */ + public File getBaseFile() { + return basefile; + } + + void setMruIndex(int index) { + mruIndex = index; + } + + int getMruIndex() { + return mruIndex; + } + + protected static void setPermissions(File nested) { + String commandProp = FrameworkProperties.getProperty(PROP_SETPERMS_CMD); + if (commandProp == null) + return; + String[] temp = ManifestElement.getArrayFromList(commandProp, " "); //$NON-NLS-1$ + ArrayList command = new ArrayList(temp.length + 1); + boolean foundFullPath = false; + for (int i = 0; i < temp.length; i++) { + if ("[fullpath]".equals(temp[i])) { //$NON-NLS-1$ + command.add(nested.getAbsolutePath()); + foundFullPath = true; + } + else + command.add(temp[i]); + } + if (!foundFullPath) + command.add(nested.getAbsolutePath()); + try { + Runtime.getRuntime().exec((String[]) command.toArray(new String[command.size()])).waitFor(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirBundleFile.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirBundleFile.java new file mode 100644 index 000000000..299311528 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirBundleFile.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.bundlefile; + +import java.io.File; +import java.io.IOException; +import java.util.Enumeration; +import java.util.NoSuchElementException; +import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg; +import org.eclipse.osgi.util.NLS; + +/** + * A BundleFile that uses a directory as its base file. + */ +public class DirBundleFile extends BundleFile { + + /** + * Constructs a DirBundleFile + * @param basefile the base file + * @throws IOException + */ + public DirBundleFile(File basefile) throws IOException { + super(basefile); + if (!BundleFile.secureAction.exists(basefile) || !BundleFile.secureAction.isDirectory(basefile)) { + throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_EXCEPTION, basefile)); + } + } + + public File getFile(String path, boolean nativeCode) { + File filePath = new File(this.basefile, path); + if (BundleFile.secureAction.exists(filePath)) { + return filePath; + } + return null; + } + + public BundleEntry getEntry(String path) { + File filePath = new File(this.basefile, path); + if (!BundleFile.secureAction.exists(filePath)) { + return null; + } + return new FileBundleEntry(filePath, path); + } + + public boolean containsDir(String dir) { + File dirPath = new File(this.basefile, dir); + return BundleFile.secureAction.exists(dirPath) && BundleFile.secureAction.isDirectory(dirPath); + } + + public Enumeration getEntryPaths(final String path) { + final java.io.File pathFile = new java.io.File(basefile, path); + if (!BundleFile.secureAction.exists(pathFile)) + return null; + if (BundleFile.secureAction.isDirectory(pathFile)) { + final String[] fileList = BundleFile.secureAction.list(pathFile); + if (fileList == null || fileList.length == 0) + return null; + final String dirPath = path.length() == 0 || path.charAt(path.length() - 1) == '/' ? path : path + '/'; + return new Enumeration() { + int cur = 0; + + public boolean hasMoreElements() { + return fileList != null && cur < fileList.length; + } + + public Object nextElement() { + if (!hasMoreElements()) { + throw new NoSuchElementException(); + } + java.io.File childFile = new java.io.File(pathFile, fileList[cur]); + StringBuffer sb = new StringBuffer(dirPath).append(fileList[cur++]); + if (BundleFile.secureAction.isDirectory(childFile)) { + sb.append("/"); //$NON-NLS-1$ + } + return sb.toString(); + } + + }; + } + return new Enumeration() { + int cur = 0; + + public boolean hasMoreElements() { + return cur < 1; + } + + public Object nextElement() { + if (cur == 0) { + cur = 1; + return path; + } + throw new NoSuchElementException(); + } + }; + } + + public void close() { + // nothing to do. + } + + public void open() { + // nothing to do. + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirZipBundleEntry.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirZipBundleEntry.java new file mode 100644 index 000000000..ce5be0c78 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/DirZipBundleEntry.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.bundlefile; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Represents a directory entry in a ZipBundleFile. This object is used to + * reference a directory entry in a ZipBundleFile when the directory entries are + * not included in the zip file. + */ +public class DirZipBundleEntry extends BundleEntry { + + /** + * ZipBundleFile for this entry. + */ + private ZipBundleFile bundleFile; + /** + * The name for this entry + */ + String name; + + public DirZipBundleEntry(ZipBundleFile bundleFile, String name) { + this.name = (name.length() > 0 && name.charAt(0) == '/') ? name.substring(1) : name; + this.bundleFile = bundleFile; + } + + public InputStream getInputStream() throws IOException { + return null; + } + + public long getSize() { + return 0; + } + + public String getName() { + return name; + } + + public long getTime() { + return 0; + } + + public URL getLocalURL() { + try { + return new URL("jar:file:" + bundleFile.basefile.getAbsolutePath() + "!/" + name); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (MalformedURLException e) { + //This can not happen, unless the jar protocol is not supported. + return null; + } + } + + public URL getFileURL() { + try { + return bundleFile.extractDirectory(name).toURL(); + } catch (MalformedURLException e) { + // this cannot happen. + return null; + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/FileBundleEntry.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/FileBundleEntry.java new file mode 100644 index 000000000..4c75e4a39 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/FileBundleEntry.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.bundlefile; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * A BundleEntry represented by a File object. The FileBundleEntry class is + * used for bundles that are installed as extracted zips on a file system. + */ +public class FileBundleEntry extends BundleEntry { + /** + * File for this entry. + */ + private File file; + /** + * The name for this entry + */ + String name; + + /** + * Constructs the BundleEntry using a File. + * @param file BundleFile object this entry is a member of + * @param name the name of this BundleEntry + */ + FileBundleEntry(File file, String name) { + this.file = file; + this.name = name; + } + + /** + * Return an InputStream for the entry. + * + * @return InputStream for the entry + * @exception java.io.IOException + */ + public InputStream getInputStream() throws IOException { + return BundleFile.secureAction.getFileInputStream(file); + } + + /** + * Return size of the uncompressed entry. + * + * @return size of entry + */ + public long getSize() { + return BundleFile.secureAction.length(file); + } + + /** + * Return name of the entry. + * + * @return name of entry + */ + public String getName() { + return (name); + } + + /** + * Get the modification time for this BundleEntry. + * <p>If the modification time has not been set, + * this method will return <tt>-1</tt>. + * + * @return last modification time. + */ + public long getTime() { + return BundleFile.secureAction.lastModified(file); + } + + public URL getLocalURL() { + return getFileURL(); + } + + public URL getFileURL() { + try { + return file.toURL(); + } catch (MalformedURLException e) { + return null; + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/MRUBundleFileList.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/MRUBundleFileList.java new file mode 100644 index 000000000..1db8eea0c --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/MRUBundleFileList.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.bundlefile; + +import java.io.IOException; + +/** + * A simple/quick/small implementation of an MRU (Most Recently Used) list to keep + * track of open BundleFiles. The MRU will use the file limit specified by the property + * "osgi.bundlefile.limit" by default unless the MRU is constructed with a specific + * file limit. + */ +public class MRUBundleFileList { + private static final String PROP_FILE_LIMIT = "osgi.bundlefile.limit"; //$NON-NLS-1$ + private static final int MIN = 10; + // list of open bundle files + private BundleFile[] bundleFileList; + // list of open bundle files use stamps + private long[] useStampList; + // the current use stamp + private long curUseStamp = 0; + // the limit of open files to allow before least used bundle file is closed + private int fileLimit = 0; // value < MIN will disable MRU + // the current number of open bundle files + private int numOpen = 0; + + public MRUBundleFileList() { + try { + String prop = BundleFile.secureAction.getProperty(PROP_FILE_LIMIT); + if (prop != null) + init(Integer.parseInt(prop)); + } catch (NumberFormatException e) { + //MRU will be disabled + } + } + + public MRUBundleFileList(int fileLimit) { + init(fileLimit); + } + + private void init(int initFileLimit) { + // only enable the MRU if the initFileLimit is > MIN + if (initFileLimit >= MIN) { + this.fileLimit = initFileLimit; + this.bundleFileList = new BundleFile[initFileLimit]; + this.useStampList = new long[initFileLimit]; + } + } + + /** + * Adds a BundleFile which is about to be opened to the MRU list. If + * the number of open BundleFiles == the fileLimit then the least + * recently used BundleFile is closed. + * @param bundleFile the bundle file about to be opened. + * @throws IOException if an error occurs while closing the least recently used BundleFile + */ + public void add(BundleFile bundleFile) throws IOException { + if (fileLimit < MIN) + return; // MRU is disabled + synchronized (bundleFileList) { + int index = 0; // default to the first slot + if (numOpen < fileLimit) { + // numOpen does not exceed the fileLimit + // find the first null slot to use in the MRU + for (int i = 0; i < fileLimit; i++) + if (bundleFileList[i] == null) { + index = i; + break; + } + } else { + // numOpen has reached the fileLimit + // find the least recently used bundleFile and close it + // and use it slot for the new bundleFile to be opened. + index = 0; + for (int i = 1; i < fileLimit; i++) + if (useStampList[i] < useStampList[index]) + index = i; + BundleFile toRemove = bundleFileList[index]; + remove(toRemove); + toRemove.close(); + } + // found an index to place to bundleFile to be opened + bundleFileList[index] = bundleFile; + bundleFile.setMruIndex(index); + incUseStamp(index); + numOpen++; + } + } + + /** + * Removes a bundle file which is about to be closed + * @param bundleFile the bundle file about to be closed + * @return true if the bundleFile existed in the MRU; false otherwise + */ + public boolean remove(BundleFile bundleFile) { + if (fileLimit < MIN) + return false; // MRU is disabled + synchronized (bundleFileList) { + int index = bundleFile.getMruIndex(); + if ((index >= 0 || index < fileLimit) && bundleFileList[index] == bundleFile) { + bundleFileList[index] = null; + useStampList[index] = -1; + numOpen--; + return true; + } + } + return false; + } + + /** + * Increments the use stamp of a bundle file + * @param bundleFile the bundle file to increment the use stamp for + */ + public void use(BundleFile bundleFile) { + if (fileLimit < MIN) + return; // MRU is disabled + synchronized (bundleFileList) { + int index = bundleFile.getMruIndex(); + if ((index >= 0 || index < fileLimit) && bundleFileList[index] == bundleFile) + incUseStamp(index); + } + } + + private void incUseStamp(int index) { + if (curUseStamp == Long.MAX_VALUE) { + // we hit the curUseStamp max better reset all the stamps + for (int i = 0; i < fileLimit; i++) + useStampList[i] = 0; + curUseStamp = 0; + } + useStampList[index] = ++curUseStamp; + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/NestedDirBundleFile.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/NestedDirBundleFile.java new file mode 100644 index 000000000..6946b6803 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/NestedDirBundleFile.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.bundlefile; + +import java.io.File; +import java.io.IOException; +import java.util.Enumeration; + +/** + * A NestedDirBundleFile uses another BundleFile as its source but + * accesses all of its resources relative to a nested directory within + * the other BundleFile object. This is used to support zipped bundles + * that use a Bundle-ClassPath with an nested directory specified. + * <p> + * For Example: + * <pre> + * Bundle-ClassPath: nested.jar,nesteddir/ + * </pre> + */ +public class NestedDirBundleFile extends BundleFile { + BundleFile baseBundleFile; + String cp; + + /** + * Constructs a NestedDirBundleFile + * @param baseBundlefile the base bundle file + * @param cp + */ + public NestedDirBundleFile(BundleFile baseBundlefile, String cp) { + super(baseBundlefile.basefile); + this.baseBundleFile = baseBundlefile; + this.cp = cp; + if (cp.charAt(cp.length() - 1) != '/') { + this.cp = this.cp + '/'; + } + } + + public void close() { + // do nothing. + } + + public BundleEntry getEntry(String path) { + if (path.length() > 0 && path.charAt(0) == '/') + path = path.substring(1); + String newpath = new StringBuffer(cp).append(path).toString(); + return baseBundleFile.getEntry(newpath); + } + + public boolean containsDir(String dir) { + if (dir == null) + return false; + + if (dir.length() > 0 && dir.charAt(0) == '/') + dir = dir.substring(1); + String newdir = new StringBuffer(cp).append(dir).toString(); + return baseBundleFile.containsDir(newdir); + } + + public Enumeration getEntryPaths(String path) { + // getEntryPaths is only valid if this is a root bundle file. + return null; + } + + public File getFile(String entry, boolean nativeCode) { + // getFile is only valid if this is a root bundle file. + return null; + } + + public void open() throws IOException { + // do nothing + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/ZipBundleEntry.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/ZipBundleEntry.java new file mode 100644 index 000000000..54de51579 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/ZipBundleEntry.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.bundlefile; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.zip.ZipEntry; + +/** + * A BundleEntry represented by a ZipEntry in a ZipFile. The ZipBundleEntry + * class is used for bundles that are installed as a ZipFile on a file system. + */ +public class ZipBundleEntry extends BundleEntry { + /** + * ZipEntry for this entry. + */ + protected ZipEntry zipEntry; + + /** + * The BundleFile for this entry. + */ + protected BundleFile bundleFile; + + /** + * Constructs the BundleEntry using a ZipEntry. + * @param bundleFile BundleFile object this entry is a member of + * @param zipEntry ZipEntry object of this entry + */ + ZipBundleEntry(ZipEntry zipEntry, BundleFile bundleFile) { + this.zipEntry = zipEntry; + this.bundleFile = bundleFile; + } + + /** + * Return an InputStream for the entry. + * + * @return InputStream for the entry + * @exception java.io.IOException + */ + public InputStream getInputStream() throws IOException { + return ((ZipBundleFile) bundleFile).getZipFile().getInputStream(zipEntry); + } + + /** + * Return size of the uncompressed entry. + * + * @return size of entry + */ + public long getSize() { + return zipEntry.getSize(); + } + + /** + * Return name of the entry. + * + * @return name of entry + */ + public String getName() { + return zipEntry.getName(); + } + + /** + * Get the modification time for this BundleEntry. + * <p>If the modification time has not been set, + * this method will return <tt>-1</tt>. + * + * @return last modification time. + */ + public long getTime() { + return zipEntry.getTime(); + } + + public URL getLocalURL() { + try { + return new URL("jar:file:" + bundleFile.basefile.getAbsolutePath() + "!/" + zipEntry.getName()); //$NON-NLS-1$//$NON-NLS-2$ + } catch (MalformedURLException e) { + //This can not happen. + return null; + } + } + + public URL getFileURL() { + try { + File file = bundleFile.getFile(zipEntry.getName(), false); + if (file != null) + return file.toURL(); + } catch (MalformedURLException e) { + //This can not happen. + } + return null; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/ZipBundleFile.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/ZipBundleFile.java new file mode 100644 index 000000000..a13f89b3a --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/bundlefile/ZipBundleFile.java @@ -0,0 +1,285 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.bundlefile; + +import java.io.*; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg; +import org.eclipse.osgi.internal.baseadaptor.AdaptorUtil; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.FrameworkEvent; + +/** + * A BundleFile that uses a ZipFile as it base file. + */ +public class ZipBundleFile extends BundleFile { + protected static MRUBundleFileList mruList = new MRUBundleFileList(); + + /** + * The bundle data + */ + protected BaseData bundledata; + /** + * The zip file + */ + protected ZipFile zipFile; + /** + * The closed flag + */ + protected boolean closed = true; + + /** + * Constructs a ZipBundle File + * @param basefile the base file + * @param bundledata the bundle data + * @throws IOException + */ + public ZipBundleFile(File basefile, BaseData bundledata) throws IOException { + super(basefile); + if (!BundleFile.secureAction.exists(basefile)) + throw new IOException(NLS.bind(AdaptorMsg.ADAPTER_FILEEXIST_EXCEPTION, basefile)); + this.bundledata = bundledata; + this.closed = true; + } + + /** + * Checks if the zip file is open + * @return true if the zip file is open + */ + protected boolean checkedOpen() { + try { + return getZipFile() != null; + } catch (IOException e) { + + bundledata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundledata.getBundle(), e); + return false; + } + } + + /** + * Opens the ZipFile for this bundle file + * @return an open ZipFile for this bundle file + * @throws IOException + */ + protected ZipFile basicOpen() throws IOException { + return BundleFile.secureAction.getZipFile(this.basefile); + } + + /** + * Returns an open ZipFile for this bundle file. If an open + * ZipFile does not exist then a new one is created and + * returned. + * @return an open ZipFile for this bundle + * @throws IOException + */ + protected ZipFile getZipFile() throws IOException { + if (closed) { + mruList.add(this); + zipFile = basicOpen(); + closed = false; + } else + mruList.use(this); + return zipFile; + } + + protected ZipEntry getZipEntry(String path) { + if (path.length() > 0 && path.charAt(0) == '/') + path = path.substring(1); + ZipEntry entry = zipFile.getEntry(path); + if (entry != null && entry.getSize() == 0 && !entry.isDirectory()) { + // work around the directory bug see bug 83542 + ZipEntry dirEntry = zipFile.getEntry(path + '/'); + if (dirEntry != null) + entry = dirEntry; + } + return entry; + } + + /** + * Extracts a directory and all sub content to disk + * @param dirName the directory name to extract + * @return the File used to extract the content to. A value + * of <code>null</code> is returned if the directory to extract does + * not exist or if content extraction is not supported. + */ + protected File extractDirectory(String dirName) { + if (!checkedOpen()) + return null; + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + String entryPath = ((ZipEntry) entries.nextElement()).getName(); + if (entryPath.startsWith(dirName) && !entryPath.endsWith("/")) //$NON-NLS-1$ + getFile(entryPath, false); + } + return getExtractFile(dirName); + } + + protected File getExtractFile(String entryName) { + String path = ".cp"; /* put all these entries in this subdir *///$NON-NLS-1$ + String name = entryName.replace('/', File.separatorChar); + if ((name.length() > 1) && (name.charAt(0) == File.separatorChar)) /* if name has a leading slash */ + path = path.concat(name); + else + path = path + File.separator + name; + return bundledata.getExtractFile(path); + } + + public File getFile(String entry, boolean nativeCode) { + if (!checkedOpen()) + return null; + ZipEntry zipEntry = getZipEntry(entry); + if (zipEntry == null) + return null; + + try { + File nested = getExtractFile(zipEntry.getName()); + if (nested != null) { + if (nested.exists()) { + /* the entry is already cached */ + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("File already present: " + nested.getPath()); //$NON-NLS-1$ + } else { + if (zipEntry.getName().endsWith("/")) { //$NON-NLS-1$ + if (!nested.mkdirs()) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("Unable to create directory: " + nested.getPath()); //$NON-NLS-1$ + throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, nested.getAbsolutePath())); + } + extractDirectory(zipEntry.getName()); + } else { + InputStream in = zipFile.getInputStream(zipEntry); + if (in == null) + return null; + /* the entry has not been cached */ + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("Creating file: " + nested.getPath()); //$NON-NLS-1$ + /* create the necessary directories */ + File dir = new File(nested.getParent()); + if (!dir.exists() && !dir.mkdirs()) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("Unable to create directory: " + dir.getPath()); //$NON-NLS-1$ + throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, dir.getAbsolutePath())); + } + /* copy the entry to the cache */ + AdaptorUtil.readFile(in, nested); + if (nativeCode) + setPermissions(nested); + } + } + + return nested; + } + } catch (IOException e) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.printStackTrace(e); + } + return null; + } + + public boolean containsDir(String dir) { + if (!checkedOpen()) + return false; + if (dir == null) + return false; + + if (dir.length() == 0) + return true; + + if (dir.charAt(0) == '/') { + if (dir.length() == 1) + return true; + dir = dir.substring(1); + } + + if (dir.length() > 0 && dir.charAt(dir.length() - 1) != '/') + dir = dir + '/'; + + Enumeration entries = zipFile.entries(); + ZipEntry zipEntry; + String entryPath; + while (entries.hasMoreElements()) { + zipEntry = (ZipEntry) entries.nextElement(); + entryPath = zipEntry.getName(); + if (entryPath.startsWith(dir)) { + return true; + } + } + return false; + } + + public BundleEntry getEntry(String path) { + if (!checkedOpen()) + return null; + ZipEntry zipEntry = getZipEntry(path); + if (zipEntry == null) { + if (path.length() == 0 || path.charAt(path.length() - 1) == '/') { + // this is a directory request lets see if any entries exist in this directory + if (containsDir(path)) + return new DirZipBundleEntry(this, path); + } + return null; + } + + return new ZipBundleEntry(zipEntry, this); + + } + + public Enumeration getEntryPaths(String path) { + if (!checkedOpen()) + return null; + if (path == null) + throw new NullPointerException(); + + if (path.length() > 0 && path.charAt(0) == '/') + path = path.substring(1); + if (path.length() > 0 && path.charAt(path.length() - 1) != '/') + path = new StringBuffer(path).append("/").toString(); //$NON-NLS-1$ + + Vector vEntries = new Vector(); + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry zipEntry = (ZipEntry) entries.nextElement(); + String entryPath = zipEntry.getName(); + if (entryPath.startsWith(path)) { + if (path.length() < entryPath.length()) { + if (entryPath.lastIndexOf('/') < path.length()) { + vEntries.add(entryPath); + } else { + entryPath = entryPath.substring(path.length()); + int slash = entryPath.indexOf('/'); + entryPath = path + entryPath.substring(0, slash + 1); + if (!vEntries.contains(entryPath)) + vEntries.add(entryPath); + } + } + } + } + return vEntries.size() == 0 ? null : vEntries.elements(); + } + + public void close() throws IOException { + if (!closed) { + closed = true; + zipFile.close(); + mruList.remove(this); + } + } + + public void open() throws IOException { + //do nothing + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/AdaptorHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/AdaptorHook.java new file mode 100644 index 000000000..2350ea861 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/AdaptorHook.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.baseadaptor.hooks; + +import java.io.IOException; +import java.net.URLConnection; +import java.util.Properties; +import org.eclipse.osgi.baseadaptor.BaseAdaptor; +import org.eclipse.osgi.baseadaptor.HookRegistry; +import org.eclipse.osgi.framework.adaptor.EventPublisher; +import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; +import org.eclipse.osgi.framework.log.FrameworkLog; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; + +/** + * An AdaptorHook hooks into the <code>BaseAdaptor</code> class. + * @see BaseAdaptor + * @see HookRegistry#getAdaptorHooks() + * @see HookRegistry#addAdaptorHook(AdaptorHook) + */ +public interface AdaptorHook { + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#initialize(EventPublisher)}. + * This method allows an adaptor hook to save the adaptor object for later. + * @param adaptor the adaptor object associated with this AdaptorHook. + */ + public void initialize(BaseAdaptor adaptor); + + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#frameworkStart(BundleContext)}. + * This method allows an adaptor hook to execute code when the framework is starting + * (e.g. to register services). + * @param context the system bundle context + * @throws BundleException if an error occurs + */ + public void frameworkStart(BundleContext context) throws BundleException; + + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#frameworkStop(BundleContext)}. + * This method allows an adaptor hook to execute code when the framework is stopped + * (e.g. to unregister services). + * @param context the system bundle context + * @throws BundleException if an error occurs. + */ + public void frameworkStop(BundleContext context) throws BundleException; + + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#frameworkStopping(BundleContext)}. + * This method allows an adaptor hook to execute code when the framework is about to start + * the shutdown process. + * @param context the system bundle context + */ + public void frameworkStopping(BundleContext context); + + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#getProperties()}. + * This method allows an adaptor hook to add property values to the adaptor + * properties object. + * @param properties the adaptor properties object. + */ + public void addProperties(Properties properties); + + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#mapLocationToURLConnection(String)}. + * The adaptor will call this method for each configured adaptor hook until one + * adaptor hook returns a non-null value. If no adaptor hook returns a non-null value + * then the adaptor will perform the default behavior. + * @param location a bundle location string to be converted to a URLConnection + * @return the URLConnection converted from the bundle location or null. + * @throws IOException if an error occured creating the URLConnection + */ + public URLConnection mapLocationToURLConnection(String location) throws IOException; + + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#handleRuntimeError(Throwable)}. + * The adaptor will call this method for each configured adaptor hook. + * @param error the unexpected error that occured. + */ + public void handleRuntimeError(Throwable error); + + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#matchDNChain(String, String[])}. + * The adaptor will call this method for each configured adaptor hook until one + * adaptor hook returns a true value. If no adaptor hook returns a true value + * then the adaptor will return false. + * @param pattern A + * @param dnChain + * @return true if the pattern matches + */ + public boolean matchDNChain(String pattern, String[] dnChain); + + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#getFrameworkLog()}. + * The adaptor will call this method for each configured adaptor hook until one + * adaptor hook returns a non-null value. If no adaptor hook returns a non-null value + * then the adaptor will return null. + * @return a FrameworkLog object or null. + */ + public FrameworkLog createFrameworkLog(); +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/BundleFileFactoryHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/BundleFileFactoryHook.java new file mode 100644 index 000000000..c0452d0fd --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/BundleFileFactoryHook.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.hooks; + +import java.io.IOException; +import org.eclipse.osgi.baseadaptor.BaseAdaptor; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; + +/** + * A factory that creates bundle file objects. + * @see BaseAdaptor#createBundleFile(Object, BaseData) + */ +public interface BundleFileFactoryHook { + /** + * Creates a bundle file for the given content and base data. + * @param content The object which contains the content of a bundle file. + * @param data The base data associated with the content + * @param base true if the content is for the base bundle (not an inner jar, directory etc.) + * @return a new bundle file for the specified content, or null if this factory cannot + * create a bundle file for the specified content. + * @throws IOException if an IO error occurs + */ + BundleFile createBundleFile(Object content, BaseData data, boolean base) throws IOException; +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/ClassLoadingHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/ClassLoadingHook.java new file mode 100644 index 000000000..bf4d2b118 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/ClassLoadingHook.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.baseadaptor.hooks; + +import java.security.ProtectionDomain; +import java.util.ArrayList; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.baseadaptor.HookRegistry; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.loader.*; +import org.eclipse.osgi.framework.adaptor.*; + +/** + * A ClassLoadingHook hooks into the <code>ClasspathManager</code> class. + * @see ClasspathManager + * @see HookRegistry#getClassLoadingHooks() + * @see HookRegistry#addClassLoadingHook(ClassLoadingHook) + */ +public interface ClassLoadingHook { + /** + * Gets called by a classpath manager before defining a class. This method allows a class loading hook + * to process the bytes of a class that is about to be defined. + * @param name the name of the class being defined + * @param classbytes the bytes of the class being defined + * @param classpathEntry the ClasspathEntry where the class bytes have been read from. + * @param entry the BundleEntry source of the class bytes + * @param manager the class path manager used to define the requested class + * @return a modified array of classbytes or null if the original bytes should be used. + */ + byte[] processClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager); + + /** + * Gets called by a classpath manager when looking for ClasspathEntry objects. This method allows + * a classloading hook to add additional ClasspathEntry objects + * @param cpEntries the list of ClasspathEntry objects currently available for the requested classpath + * @param cp the name of the requested classpath + * @param hostmanager the classpath manager the requested ClasspathEntry is for + * @param sourcedata the source bundle data of the requested ClasspathEntry + * @param sourcedomain the source domain of the requested ClasspathEntry + * @return true if a ClasspathEntry has been added to cpEntries + */ + boolean addClassPathEntry(ArrayList cpEntries, String cp, ClasspathManager hostmanager, BaseData sourcedata, ProtectionDomain sourcedomain); + + /** + * Gets called by a base data during {@link BundleData#findLibrary(String)}. + * A base data will call this method for each configured class loading hook until one + * class loading hook returns a non-null value. If no class loading hook returns + * a non-null value then the base data will return null. + * @param data the base data to find a native library for. + * @param libName the name of the native library. + * @return The absolute path name of the native library or null. + */ + String findLibrary(BaseData data, String libName); + + /** + * Gets called by the adaptor during {@link FrameworkAdaptor#getBundleClassLoaderParent()}. + * The adaptor will call this method for each configured class loading hook until one + * class loading hook returns a non-null value. If no class loading hook returns + * a non-null value then the adaptor will perform the default behavior. + * @return the parent classloader to be used by all bundle classloaders or null. + */ + public ClassLoader getBundleClassLoaderParent(); + + /** + * Gets called by a base data during + * {@link BundleData#createClassLoader(ClassLoaderDelegate, BundleProtectionDomain, String[])}. + * The BaseData will call this method for each configured class loading hook until one data + * hook returns a non-null value. If no class loading hook returns a non-null value then a + * default implemenation of BundleClassLoader will be created. + * @param parent the parent classloader for the BundleClassLoader + * @param delegate the delegate for the bundle classloader + * @param domain the domian for the bundle classloader + * @param data the BundleData for the BundleClassLoader + * @param bundleclasspath the classpath for the bundle classloader + * @return a newly created bundle classloader + */ + BaseClassLoader createClassLoader(ClassLoader parent, ClassLoaderDelegate delegate, BundleProtectionDomain domain, BaseData data, String[] bundleclasspath); + + /** + * Gets called by a base data during + * {@link BundleData#createClassLoader(ClassLoaderDelegate, BundleProtectionDomain, String[])}. + * The BaseData will call this method for each configured class loading hook after a + * BundleClassLoader has been created. + * @param baseClassLoader the newly created bundle classloader + * @param data the BundleData associated with the bundle classloader + */ + void initializedClassLoader(BaseClassLoader baseClassLoader, BaseData data); +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/ClassLoadingStatsHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/ClassLoadingStatsHook.java new file mode 100644 index 000000000..8a282a29e --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/ClassLoadingStatsHook.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2006 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.baseadaptor.hooks; + +import java.net.URL; +import org.eclipse.osgi.baseadaptor.HookRegistry; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.loader.ClasspathEntry; +import org.eclipse.osgi.baseadaptor.loader.ClasspathManager; + +/** + * A ClassLoadingStatsHook hooks into the <code>ClasspathManager</code> class. This class allows + * a hook to record statistics about classloading. + * @see ClasspathManager + * @see HookRegistry#getClassLoadingStatsHooks() + * @see HookRegistry#addClassLoadingStatsHook(ClassLoadingStatsHook) + */ +public interface ClassLoadingStatsHook { + /** + * Gets called by a classpath manager during {@link ClasspathManager#findLocalClass(String)} before + * searching the local classloader for a class. A classpath manager will call this method for + * each configured class loading stat hook. + * @param name the name of the requested class + * @param manager the classpath manager used to find and load the requested class + * @throws ClassNotFoundException to prevent the requested class from loading + */ + void preFindLocalClass(String name, ClasspathManager manager) throws ClassNotFoundException; + + /** + * Gets called by a classpath manager during {@link ClasspathManager#findLocalClass(String)} after + * searching the local classloader for a class. A classpath manager will call this method for + * each configured class loading stat hook. + * @param name the name of the requested class + * @param clazz the loaded class or null if not found + * @param manager the classpath manager used to find and load the requested class + */ + void postFindLocalClass(String name, Class clazz, ClasspathManager manager); + + /** + * Gets called by a classpath manager during {@link ClasspathManager#findLocalResource(String)} before + * searching the local classloader for a resource. A classpath manager will call this method for + * each configured class loading stat hook. + * @param name the name of the requested resource + * @param manager the classpath manager used to find the requested resource + */ + void preFindLocalResource(String name, ClasspathManager manager); + + /** + * Gets called by a classpath manager during {@link ClasspathManager#findLocalResource(String)} after + * searching the local classloader for a resource. A classpath manager will call this method for + * each configured class loading stat hook. + * @param name the name of the requested resource + * @param resource the URL to the requested resource or null if not found + * @param manager the classpath manager used to find the requested resource + */ + void postFindLocalResource(String name, URL resource, ClasspathManager manager); + + /** + * Gets called by a classpath manager after a successfully defining a class. This method allows + * a class loading stat hook to record data about a class definition. + * @param name the name of the class that got defined + * @param clazz the class object that got defined + * @param classbytes the class bytes used to define the class + * @param classpathEntry the ClasspathEntry where the class bytes got read from + * @param entry the BundleEntyr source of the class bytes + * @param manager the classpath manager used to define the class + */ + void recordClassDefine(String name, Class clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager); + +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/StorageHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/StorageHook.java new file mode 100644 index 000000000..114ce062d --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/hooks/StorageHook.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.baseadaptor.hooks; + +import java.io.*; +import java.util.Dictionary; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.framework.adaptor.BundleData; +import org.eclipse.osgi.framework.util.KeyedElement; +import org.osgi.framework.BundleException; + +/** + * A StorageHook hooks into the persistent storage loading and saving. A StorageHook gets + * associated with each BaseData object installed in the adaptor.<p> + * A StorageHook extends {@link KeyedElement}, the key used for the element must be the + * fully qualified string name of the StorageHook implementation class. + * @see BaseData#getStorageHook(String) + */ +public interface StorageHook extends KeyedElement { + /** + * Returns the storage version of this storage hook. This version + * is used by the storage to check the consistency of cached persistent + * data. Any time a storage hook changes the format of its persistent + * data the storage version should be incremented. + * @return the storage version of this storage hook + */ + int getStorageVersion(); + + /** + * Creates an uninitialized storage hook for the specified bundledata. This method + * is called when a bundle is installed or updated. The returned storage hook will be + * used for the new contents of the bundle. The returned hook will have its + * {@link #initialize(Dictionary)} method called to initialize the storage hook. + * @param bundledata a base data the created storage hook will be associated with + * @return an uninitialized storage hook + * @throws BundleException if any error occurs + */ + StorageHook create(BaseData bundledata) throws BundleException; + + /** + * Initializes this storage hook with the content of the specified bundle manifest. + * This method is called when a bundle is installed or updated. + * @see #create(BaseData) + * @see #copy(StorageHook) + * @param manifest the bundle manifest to load into this storage hook + * @throws BundleException if any error occurs + */ + void initialize(Dictionary manifest) throws BundleException; + + /** + * Creates a new storage hook and loads the data from the specified + * input stream into the storage hook. This method is called during startup to + * load all the persistently installed bundles. <p> + * It is important that this method and the {@link #save(DataOutputStream)} method + * stay in sync. This method must be able to successfully read the data saved by the + * {@link #save(DataOutputStream)} method. + * @param bundledata a base data the loaded storage hook will be associated with + * @param is an input stream used to load the storage hook's data from. + * @return a loaded storage hook + * @see #save(DataOutputStream) + * @throws IOException if any error occurs + */ + StorageHook load(BaseData bundledata, DataInputStream is) throws IOException; + + /** + * Saves the data from this storage hook into the specified output stream. This method + * is called if some persistent data has changed for the bundle. <p> + * It is important that this method and the {@link #load(BaseData, DataInputStream)} + * method stay in sync. This method must be able to save data which the + * {@link #load(BaseData, DataInputStream)} method can ready successfully. + * @see #load(BaseData, DataInputStream) + * @param os an output stream used to save the storage hook's data from. + * @throws IOException if any error occurs + */ + void save(DataOutputStream os) throws IOException; + + /** + * Copies the data from the specified storage hook into this storage hook. This method + * is called when a bundle is updated to copy the data from the original bundle to a + * new storage hook. Then this storage will be initialized with the new bundle's + * manifest using the {@link #initialize(Dictionary)} method. + * @see #create(BaseData) + * @see #initialize(Dictionary) + * @param storageHook the original storage hook to copy data out of. + */ + void copy(StorageHook storageHook); + + /** + * Validates the data in this storage hook, if the data is invalid then an illegal state + * exception is thrown + * @throws IllegalArgumentException if the data is invalid + */ + void validate() throws IllegalArgumentException; + + /** + * Returns the manifest for the data in this storage hook, or null if this hook does + * not provide the manifest. Most hooks should return null from this method. This + * method may be used to provide special handling of manifest loading. For example, + * to provide a cached manfest or to do automatic manifest generation. + * @param firstLoad true if this is the very first time this manifest is being loaded. + * @return the manifest for the data in this storage hook, or null if this hook does + * not provide the manifest + * @throws BundleException + */ + Dictionary getManifest(boolean firstLoad) throws BundleException; + + /** + * Gets called by a base data during {@link BundleData#setStatus(int)}. + * A base data will call this method for each configured storage hook it + * is associated with until one storage hook returns true. If all configured storage + * hooks return false then the BaseData will be marked dirty and will cause the + * status to be persistently saved. + * @param status the new status of the base data + * @return false if the status is not to be persistently saved; otherwise true is returned + */ + boolean forgetStatusChange(int status); + + /** + * Gets called by a base data during {@link BundleData#setStartLevel(int)}. + * A base data will call this method for each configured storage hook it + * is associated with until one storage hook returns true. If all configured storage + * hooks return false then the BaseData will be marked dirty and will cause the + * start level to be persistently saved. + * @param startlevel the new startlevel of the base data + * @return false if the startlevel is not to be persistently saved; otherwise true is returned + */ + boolean forgetStartLevelChange(int startlevel); + + /** + * Gets called by a base data during {@link BundleData#matchDNChain(String)}. + * A base data will call this method for each configured storage hook it + * is associated with until one storage hook returns true. If all configured storage + * hooks return false value then the BaseAdaptor will return false. + * @param pattern the pattern of distinguished name (DN) chains to match + * @return true if the pattern matches. A value of false is returned + * if bundle signing is not supported. + */ + boolean matchDNChain(String pattern); +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/BaseClassLoader.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/BaseClassLoader.java new file mode 100644 index 000000000..a93dffbbe --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/BaseClassLoader.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.loader; + +import java.net.URL; +import java.security.ProtectionDomain; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; +import org.eclipse.osgi.framework.adaptor.BundleClassLoader; + +/** + * The actual class loader object used to define classes for a classpath manager. + * This interface provides public versions of a few methods on class loader. + * @see ClasspathManager + */ +public interface BaseClassLoader extends BundleClassLoader { + /** + * Returns the domain for the host bundle of this class loader + * @return the domain for the host bundle of this class loader + */ + ProtectionDomain getDomain(); + + /** + * Creates a classpath entry with the given bundle file and domain + * @param bundlefile the source bundle file for a classpath entry + * @param cpDomain the source domain for a classpath entry + * @return a classpath entry with the given bundle file and domain + */ + ClasspathEntry createClassPathEntry(BundleFile bundlefile, ProtectionDomain cpDomain); + + /** + * Defines a Class. + * @param name the name of the class to define + * @param classbytes the bytes of the class to define + * @param classpathEntry the classpath entry used to load the class bytes + * @param entry the bundle entry used to load the class bytes + * @return a defined Class + */ + Class defineClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry); + + /** + * A public version of the {@link ClassLoader#findLoadedClass(java.lang.String)} method. + * @param classname the class name to find. + * @return a loaded class + */ + Class publicFindLoaded(String classname); + + /** + * A public version of the {@link ClassLoader#getPackage(java.lang.String)} method. + * @param pkgname the package name to get. + * @return the package or null if it does not exist + */ + Object publicGetPackage(String pkgname); + + /** + * A public version of the {@link ClassLoader#definePackage(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.net.URL)} method. + * @return a defined Package + */ + Object publicDefinePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase); + + /** + * Returns the ClasspathManager for this BaseClassLoader + * @return the ClasspathManager + */ + ClasspathManager getClasspathManager(); +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathEntry.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathEntry.java new file mode 100644 index 000000000..3ddbfcd1b --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathEntry.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.loader; + +import java.security.ProtectionDomain; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; +import org.eclipse.osgi.framework.util.KeyedElement; +import org.eclipse.osgi.framework.util.KeyedHashSet; + +/** + * A ClasspathEntry contains a single <code>BundleFile</code> which is used as + * a source to load classes and resources from, and a single + * <code>ProtectionDomain</code> which is used as the domain to define classes + * loaded from this ClasspathEntry. + */ +public class ClasspathEntry { + private BundleFile bundlefile; + private ProtectionDomain domain; + private KeyedHashSet userObjects = null; + + /** + * Constructs a ClasspathElement with the specified bundlefile and domain + * @param bundlefile A BundleFile object which acts as a source + * @param domain the ProtectDomain for all code loaded from this classpath element + */ + public ClasspathEntry(BundleFile bundlefile, ProtectionDomain domain) { + this.bundlefile = bundlefile; + this.domain = domain; + } + + /** + * Returns the source BundleFile for this classpath entry + * @return the source BundleFile for this classpath entry + */ + public BundleFile getBundleFile() { + return bundlefile; + } + + /** + * Returns the ProtectionDomain for this classpath entry + * @return the ProtectionDomain for this classpath entry + */ + public ProtectionDomain getDomain() { + return domain; + } + + /** + * Returns a user object which is keyed by the specified key + * @param key the key of the user object to get + * @return a user object which is keyed by the specified key + */ + public Object getUserObject(Object key) { + if (userObjects == null) + return null; + synchronized (userObjects) { + return userObjects.getByKey(key); + } + } + + /** + * Adds a user object + * @param userObject the user object to add + */ + public synchronized void addUserObject(KeyedElement userObject) { + if (userObjects == null) + userObjects = new KeyedHashSet(5, false); + synchronized (userObjects) { + userObjects.add(userObject); + } + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java new file mode 100644 index 000000000..7291e8e7c --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/ClasspathManager.java @@ -0,0 +1,572 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.baseadaptor.loader; + +import java.io.*; +import java.net.URL; +import java.security.ProtectionDomain; +import java.util.*; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.baseadaptor.bundlefile.*; +import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook; +import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingStatsHook; +import org.eclipse.osgi.framework.adaptor.BundleData; +import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.BundleException; +import org.osgi.framework.FrameworkEvent; + +/** + * A helper class for <code>BaseClassLoader</code> implementations. This class will keep track of + * <code>ClasspathEntry</code> objects for the host bundle and any attached fragment bundles. This + * class takes care of seaching the <code>ClasspathEntry</code> objects for a base class loader + * implementation. Additional behavior may be added to a classpath manager by configuring + * <code>ClassLoadingHook</code> and <code>ClassLoadingStatsHook</code>. + * @see BaseClassLoader + * @see ClassLoadingHook + * @see ClassLoadingStatsHook + */ +public class ClasspathManager { + private static final FragmentClasspath[] emptyFragments = new FragmentClasspath[0]; + private static final int BUF_SIZE = 8 * 1024; + + private BaseData data; + private String[] classpath; + private ClasspathEntry[] entries; + private BaseClassLoader classloader; + private FragmentClasspath[] fragments = emptyFragments; + + /** + * Constructs a classpath manager for the given host base data, classpath and base class loader + * @param data the host base data for this classpath manager + * @param classpath the host classpath for this classpath manager + * @param classloader the BaseClassLoader for this classpath manager + */ + public ClasspathManager(BaseData data, String[] classpath, BaseClassLoader classloader) { + this.data = data; + this.classpath = classpath; + this.classloader = classloader; + } + + /** + * initializes this classpath manager. This must be called after all existing fragments have been + * attached and before any resources/classes are loaded using this classpath manager. + */ + public void initialize() { + entries = buildClasspath(classpath, this, data, classloader.getDomain()); + } + + /** + * Closes all the classpath entry resources for this classpath manager. + * + */ + public void close() { + if (entries != null) { + for (int i = 0; i < entries.length; i++) { + if (entries[i] != null) { + try { + entries[i].getBundleFile().close(); + } catch (IOException e) { + data.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, data.getBundle(), e); + } + } + } + } + for (int i = 0; i < fragments.length; i++) + fragments[i].close(); + } + + /** + * Attaches the specified sourcedata, sourcedomain and sourceclasspath to this classpath manager + * @param sourcedata the source fragment BundleData that should be attached. + * @param sourcedomain the source fragment domain that should be attached. + * @param sourceclasspath the source fragment classpath that should be attached. + */ + public void attachFragment(BundleData sourcedata, ProtectionDomain sourcedomain, String[] sourceclasspath) { + try { + sourcedata.open(); /* make sure the BundleData is open */ + } catch (IOException e) { + ((BaseData) sourcedata).getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, ((BaseData) sourcedata).getBundle(), e); + } + ClasspathEntry[] fragEntries = buildClasspath(sourceclasspath, this, (BaseData) sourcedata, sourcedomain); + FragmentClasspath fragClasspath = new FragmentClasspath((BaseData) sourcedata, fragEntries, sourcedomain); + insertFragment(fragClasspath); + } + + private synchronized void insertFragment(FragmentClasspath fragClasspath) { + FragmentClasspath[] newFragments = new FragmentClasspath[fragments.length + 1]; + // Find a place in the fragment list to insert this fragment. + long fragID = fragClasspath.getBundleData().getBundleID(); + int insert = 0; + for (int i = 0; i < fragments.length; i++) { + long otherID = fragments[i].getBundleData().getBundleID(); + if (insert == 0 && fragID < otherID) { + newFragments[i] = fragClasspath; + insert = 1; + } + newFragments[i + insert] = fragments[i]; + } + // This fragment has the highest ID; put it at the end of the list. + if (insert == 0) + newFragments[fragments.length] = fragClasspath; + fragments = newFragments; + } + + private static ClasspathEntry[] buildClasspath(String[] cp, ClasspathManager hostloader, BaseData sourcedata, ProtectionDomain sourcedomain) { + ArrayList result = new ArrayList(cp.length); + // add the regular classpath entries. + for (int i = 0; i < cp.length; i++) + findClassPathEntry(result, cp[i], hostloader, sourcedata, sourcedomain); + return (ClasspathEntry[]) result.toArray(new ClasspathEntry[result.size()]); + } + + /** + * Finds all the ClasspathEntry objects for the requested classpath. This method will first call all + * the configured class loading hooks {@link ClassLoadingHook#addClassPathEntry(ArrayList, String, ClasspathManager, BaseData, ProtectionDomain)} + * methods. This allows class loading hooks to add additional ClasspathEntry objects to the result for the + * requested classpath. Then the local host classpath entries and attached fragment classpath entries are + * searched. + * @param result a list of ClasspathEntry objects. This list is used to add new ClasspathEntry objects to. + * @param cp the requested classpath. + * @param hostloader the host classpath manager for the classpath + * @param sourcedata the source EquionoxData to search for the classpath + * @param sourcedomain the source domain to used by the new ClasspathEntry + */ + public static void findClassPathEntry(ArrayList result, String cp, ClasspathManager hostloader, BaseData sourcedata, ProtectionDomain sourcedomain) { + // look in classpath manager hooks first + ClassLoadingHook[] loaderHooks = sourcedata.getAdaptor().getHookRegistry().getClassLoadingHooks(); + boolean hookAdded = false; + for (int i = 0; i < loaderHooks.length; i++) + hookAdded |= loaderHooks[i].addClassPathEntry(result, cp, hostloader, sourcedata, sourcedomain); + if (!addClassPathEntry(result, cp, hostloader, sourcedata, sourcedomain) && !hookAdded) { + BundleException be = new BundleException(NLS.bind(AdaptorMsg.BUNDLE_CLASSPATH_ENTRY_NOT_FOUND_EXCEPTION, cp, sourcedata.getLocation())); + sourcedata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.INFO, sourcedata.getBundle(), be); + } + } + + /** + * Adds a ClasspathEntry for the requested classpath to the result. The local host classpath entries + * are searched first and then attached fragments classpath entries are searched. The search stops once the first + * classpath entry is found. + * @param result a list of ClasspathEntry objects. This list is used to add new ClasspathEntry objects to. + * @param cp the requested classpath. + * @param hostloader the host classpath manager for the classpath + * @param sourcedata the source EquionoxData to search for the classpath + * @param sourcedomain the source domain to used by the new ClasspathEntry + * @return true if a ClasspathEntry was added to the result + */ + public static boolean addClassPathEntry(ArrayList result, String cp, ClasspathManager hostloader, BaseData sourcedata, ProtectionDomain sourcedomain) { + if (cp.equals(".")) { //$NON-NLS-1$ + result.add(hostloader.createClassPathEntry(sourcedata.getBundleFile(), sourcedomain)); + return true; + } + Object element = hostloader.getClasspath(cp, sourcedata, sourcedomain); + if (element != null) { + result.add(element); + return true; + } + // need to check in fragments for the classpath entry. + // only check for fragments if the data is the host's data. + if (hostloader.data == sourcedata) + for (int i = 0; i < hostloader.fragments.length; i++) { + FragmentClasspath fragCP = hostloader.fragments[i]; + element = hostloader.getClasspath(cp, fragCP.getBundleData(), fragCP.getDomain()); + if (element != null) { + result.add(element); + return true; + } + } + return false; + } + + /** + * Creates a new ClasspathEntry object for the requested classpath if the source exists. + * @param cp the requested classpath. + * @param sourcedata the source EquionoxData to search for the classpath + * @param sourcedomain the source domain to used by the new ClasspathEntry + * @return a new ClasspathEntry for the requested classpath or null if the source does not exist. + */ + public ClasspathEntry getClasspath(String cp, BaseData sourcedata, ProtectionDomain sourcedomain) { + BundleFile bundlefile = null; + File file; + // check for internal library jars + if ((file = sourcedata.getBundleFile().getFile(cp, false)) != null) + bundlefile = createBundleFile(file, sourcedata); + // check for internal library directories in a bundle jar file + if (bundlefile == null && sourcedata.getBundleFile().containsDir(cp)) + bundlefile = new NestedDirBundleFile(sourcedata.getBundleFile(), cp); + // if in dev mode, try using the cp as an absolute path + if (bundlefile != null) + return createClassPathEntry(bundlefile, sourcedomain); + return null; + } + + /** + * Uses the requested classpath as an absolute path to locate a source for a new ClasspathEntry. + * @param cp the requested classpath + * @param sourcedata the source EquionoxData to search for the classpath + * @param sourcedomain the source domain to used by the new ClasspathEntry + * @return a classpath entry which uses an absolut path as a source + */ + public ClasspathEntry getExternalClassPath(String cp, BaseData sourcedata, ProtectionDomain sourcedomain) { + File file = new File(cp); + if (!file.isAbsolute()) + return null; + BundleFile bundlefile = createBundleFile(file, sourcedata); + if (bundlefile != null) + return createClassPathEntry(bundlefile, sourcedomain); + return null; + } + + private static BundleFile createBundleFile(File file, BaseData sourcedata) { + if (file == null || !file.exists()) + return null; + try { + return sourcedata.getAdaptor().createBundleFile(file, sourcedata); + } catch (IOException e) { + sourcedata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, sourcedata.getBundle(), e); + } + return null; + } + + private ClasspathEntry createClassPathEntry(BundleFile bundlefile, ProtectionDomain cpDomain) { + return classloader.createClassPathEntry(bundlefile, cpDomain); + } + + /** + * Finds a local resource by searching the ClasspathEntry objects of the classpath manager. + * This method will first call all the configured class loading stats hooks + * {@link ClassLoadingStatsHook#preFindLocalResource(String, ClasspathManager)} methods. Then it + * will search for the resource. Finally it will call all the configured class loading stats hooks + * {@link ClassLoadingStatsHook#postFindLocalResource(String, URL, ClasspathManager)} methods. + * @param resource the requested resource name. + * @return the requested resource URL or null if the resource does not exist + */ + public URL findLocalResource(String resource) { + ClassLoadingStatsHook[] hooks = data.getAdaptor().getHookRegistry().getClassLoadingStatsHooks(); + for (int i = 0; i < hooks.length; i++) + hooks[i].preFindLocalResource(resource, this); + URL result = null; + try { + result = findLocalResourceImpl(resource); + return result; + } finally { + for (int i = 0; i < hooks.length; i++) + hooks[i].postFindLocalResource(resource, result, this); + } + } + + private URL findLocalResourceImpl(String resource) { + URL result = null; + for (int i = 0; i < entries.length; i++) { + if (entries[i] != null) { + result = findResourceImpl(resource, entries[i].getBundleFile()); + if (result != null) + return result; + } + } + // look in fragments + for (int i = 0; i < fragments.length; i++) { + ClasspathEntry[] fragEntries = fragments[i].getEntries(); + for (int j = 0; j < fragEntries.length; j++) { + result = findResourceImpl(resource, fragEntries[j].getBundleFile()); + if (result != null) + return result; + } + } + return null; + } + + /** + * Finds the local resources by searching the ClasspathEntry objects of the classpath manager. + * @param resource the requested resource name. + * @return an enumeration of the the requested resources or null if the resources do not exist + */ + public Enumeration findLocalResources(String resource) { + Vector resources = new Vector(6); // use a Vector instead of ArrayList because we need an enumeration + for (int i = 0; i < entries.length; i++) { + if (entries[i] != null) { + URL url = findResourceImpl(resource, entries[i].getBundleFile(), resources.size()); + if (url != null) + resources.addElement(url); + } + } + // look in fragments + for (int i = 0; i < fragments.length; i++) { + ClasspathEntry[] fragEntries = fragments[i].getEntries(); + for (int j = 0; j < fragEntries.length; j++) { + URL url = findResourceImpl(resource, fragEntries[j].getBundleFile(), resources.size()); + if (url != null) + resources.addElement(url); + } + } + if (resources.size() > 0) + return resources.elements(); + return null; + } + + private URL findResourceImpl(String name, BundleFile bundlefile) { + return findResourceImpl(name, bundlefile, 0); + } + + private URL findResourceImpl(String name, BundleFile bundlefile, int index) { + return bundlefile.getResourceURL(name, data.getBundleID(), index); + } + + /** + * Finds a local entry by searching the ClasspathEntry objects of the classpath manager. + * @param path the requested entry path. + * @return the requested entry or null if the entry does not exist + */ + public BundleEntry findLocalEntry(String path) { + BundleEntry result = null; + for (int i = 0; i < entries.length; i++) { + if (entries[i] != null) { + result = findEntryImpl(path, entries[i].getBundleFile()); + if (result != null) + return result; + } + } + // look in fragments + for (int i = 0; i < fragments.length; i++) { + ClasspathEntry[] fragEntries = fragments[i].getEntries(); + for (int j = 0; j < fragEntries.length; j++) { + result = findEntryImpl(path, fragEntries[j].getBundleFile()); + if (result != null) + return result; + } + } + return null; + } + + /** + * Finds the local entries by searching the ClasspathEntry objects of the classpath manager. + * @param path the requested entry path. + * @return an enumeration of the the requested entries or null if the entries do not exist + */ + public Enumeration findLocalEntries(String path) { + Vector objects = new Vector(6); // use a Vector instead of ArrayList because we need an enumeration + for (int i = 0; i < entries.length; i++) { + if (entries[i] != null) { + BundleEntry result = findEntryImpl(path, entries[i].getBundleFile()); + if (result != null) + objects.addElement(result); + } + } + // look in fragments + for (int i = 0; i < fragments.length; i++) { + ClasspathEntry[] fragEntries = fragments[i].getEntries(); + for (int j = 0; j < fragEntries.length; j++) { + BundleEntry result = findEntryImpl(path, fragEntries[j].getBundleFile()); + if (result != null) + objects.addElement(result); + } + } + if (objects.size() > 0) + return objects.elements(); + return null; + } + + private BundleEntry findEntryImpl(String path, BundleFile bundleFile) { + return bundleFile.getEntry(path); + } + + /** + * Finds a local class by searching the ClasspathEntry objects of the classpath manager. + * This method will first call all the configured class loading stats hooks + * {@link ClassLoadingStatsHook#preFindLocalClass(String, ClasspathManager)} methods. Then it + * will search for the class. If a class is found then all configured class loading hooks + * {@link ClassLoadingHook#processClass(String, byte[], ClasspathEntry, BundleEntry, ClasspathManager)} + * methods will be called. Finally all the configured class loading stats hooks + * {@link ClassLoadingStatsHook#postFindLocalClass(String, Class, ClasspathManager)} methods are called. + * @param classname the requested class name. + * @return the requested class + * @throws ClassNotFoundException if the class does not exist + */ + public Class findLocalClass(String classname) throws ClassNotFoundException { + Class result = null; + ClassLoadingStatsHook[] hooks = data.getAdaptor().getHookRegistry().getClassLoadingStatsHooks(); + try { + for (int i = 0; i < hooks.length; i++) + hooks[i].preFindLocalClass(classname, this); + result = findLocalClassImpl(classname, hooks); + return result; + } finally { + for (int i = 0; i < hooks.length; i++) + hooks[i].postFindLocalClass(classname, result, this); + } + } + + private Class findLocalClassImpl(String classname, ClassLoadingStatsHook[] hooks) throws ClassNotFoundException { + // must call findLoadedClass here even if it was called earlier, + // the findLoadedClass and defineClass calls must be atomic + synchronized (classloader) { + Class result = classloader.publicFindLoaded(classname); + if (result != null) + return result; + for (int i = 0; i < entries.length; i++) { + if (entries[i] != null) { + result = findClassImpl(classname, entries[i], hooks); + if (result != null) + return result; + } + } + // look in fragments. + for (int i = 0; i < fragments.length; i++) { + ClasspathEntry[] fragEntries = fragments[i].getEntries(); + for (int j = 0; j < fragEntries.length; j++) { + result = findClassImpl(classname, fragEntries[j], hooks); + if (result != null) + return result; + } + } + } + throw new ClassNotFoundException(classname); + } + + private Class findClassImpl(String name, ClasspathEntry classpathEntry, ClassLoadingStatsHook[] hooks) { + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println("BundleClassLoader[" + data + "].findClass(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ + String filename = name.replace('.', '/').concat(".class"); //$NON-NLS-1$ + BundleEntry entry = classpathEntry.getBundleFile().getEntry(filename); + if (entry == null) + return null; + + InputStream in; + try { + in = entry.getInputStream(); + } catch (IOException e) { + return null; + } + + int length = (int) entry.getSize(); + byte[] classbytes; + int bytesread = 0; + int readcount; + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println(" about to read " + length + " bytes from " + filename); //$NON-NLS-1$ //$NON-NLS-2$ + + try { + try { + if (length > 0) { + classbytes = new byte[length]; + readloop: for (; bytesread < length; bytesread += readcount) { + readcount = in.read(classbytes, bytesread, length - bytesread); + if (readcount <= 0) /* if we didn't read anything */ + break readloop; /* leave the loop */ + } + } else /* BundleEntry does not know its own length! */{ + length = BUF_SIZE; + classbytes = new byte[length]; + readloop: while (true) { + for (; bytesread < length; bytesread += readcount) { + readcount = in.read(classbytes, bytesread, length - bytesread); + if (readcount <= 0) /* if we didn't read anything */ + break readloop; /* leave the loop */ + } + byte[] oldbytes = classbytes; + length += BUF_SIZE; + classbytes = new byte[length]; + System.arraycopy(oldbytes, 0, classbytes, 0, bytesread); + } + } + if (classbytes.length > bytesread) { + byte[] oldbytes = classbytes; + classbytes = new byte[bytesread]; + System.arraycopy(oldbytes, 0, classbytes, 0, bytesread); + } + } catch (IOException e) { + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println(" IOException reading " + filename + " from " + data); //$NON-NLS-1$ //$NON-NLS-2$ + return null; + } + } finally { + try { + in.close(); + } catch (IOException ee) { + // nothing to do here + } + } + + if (Debug.DEBUG && Debug.DEBUG_LOADER) { + Debug.println(" read " + bytesread + " bytes from " + filename); //$NON-NLS-1$ //$NON-NLS-2$ + Debug.println(" defining class " + name); //$NON-NLS-1$ + } + + try { + Class result = defineClass(name, classbytes, classpathEntry, entry); + for (int i = 0; i < hooks.length; i++) + hooks[i].recordClassDefine(name, result, classbytes, classpathEntry, entry, this); + return result; + } catch (Error e) { + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println(" error defining class " + name); //$NON-NLS-1$ + throw e; + } + } + + /** + * Defines the specified class. This method will first call all the configured class loading hooks + * {@link ClassLoadingHook#processClass(String, byte[], ClasspathEntry, BundleEntry, ClasspathManager)} + * methods. Then it will call the {@link BaseClassLoader#defineClass(String, byte[], ClasspathEntry, BundleEntry)} + * method to define the class. + * @param name the name of the class to define + * @param classbytes the class bytes + * @param classpathEntry the classpath entry used to load the class bytes + * @param entry the BundleEntry used to load the class bytes + * @return the defined class + */ + private Class defineClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry) { + ClassLoadingHook[] hooks = data.getAdaptor().getHookRegistry().getClassLoadingHooks(); + byte[] modifiedBytes = classbytes; + for (int i = 0; i < hooks.length; i++) { + modifiedBytes = hooks[i].processClass(name, classbytes, classpathEntry, entry, this); + if (modifiedBytes != null) + classbytes = modifiedBytes; + } + return classloader.defineClass(name, classbytes, classpathEntry, entry); + } + + /** + * Returns the host base data for this classpath manager + * @return the host base data for this classpath manager + */ + public BaseData getBaseData() { + return data; + } + + /** + * Returns the fragment classpaths of this classpath manager + * @return the fragment classpaths of this classpath manager + */ + public FragmentClasspath[] getFragmentClasspaths() { + return fragments; + } + + /** + * Returns the host classpath entries for this classpath manager + * @return the host classpath entries for this classpath manager + */ + public ClasspathEntry[] getHostClasspathEntries() { + return entries; + } + + /** + * Returns the base class loader used by this classpath manager + * @return the base class loader used by this classpath manager + */ + public BaseClassLoader getBaseClassLoader() { + return classloader; + } + +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/FragmentClasspath.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/FragmentClasspath.java new file mode 100644 index 000000000..89ae2cfde --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/baseadaptor/loader/FragmentClasspath.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2005 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.baseadaptor.loader; + +import java.io.IOException; +import java.security.ProtectionDomain; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.osgi.framework.FrameworkEvent; + +/** + * A FragmentClasspath contains all the <code>ClasspathEntry</code> objects for a fragment + * <code>BaseData</code>. + */ +public class FragmentClasspath { + private BaseData bundledata; + private ClasspathEntry[] entries; + private ProtectionDomain domain; + + public FragmentClasspath(BaseData bundledata, ClasspathEntry[] entries, ProtectionDomain domain) { + this.bundledata = bundledata; + this.entries = entries; + this.domain = domain; + } + + /** + * Returns the fragment BaseData for this FragmentClasspath + * @return the fragment BaseData for this FragmentClasspath + */ + public BaseData getBundleData() { + return bundledata; + } + + /** + * Returns the fragment domain for this FragmentClasspath + * @return the fragment domain for this FragmentClasspath + */ + public ProtectionDomain getDomain() { + return domain; + } + + /** + * Returns the fragment classpath entries for this FragmentClasspath + * @return the fragment classpath entries for this FragmentClasspath + */ + public ClasspathEntry[] getEntries() { + return entries; + } + + /** + * Closes all the classpath entry resources for this FragmentClasspath. + * + */ + public void close() { + for (int i = 0; i < entries.length; i++) { + try { + entries[i].getBundleFile().close(); + } catch (IOException e) { + bundledata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundledata.getBundle(), e); + } + } + } + +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AbstractBundleData.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AbstractBundleData.java deleted file mode 100644 index e5d660599..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AbstractBundleData.java +++ /dev/null @@ -1,846 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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.adaptor.core; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.*; -import org.eclipse.osgi.framework.adaptor.*; -import org.eclipse.osgi.framework.debug.Debug; -import org.eclipse.osgi.framework.internal.core.Constants; -import org.eclipse.osgi.framework.internal.protocol.bundleentry.Handler; -import org.eclipse.osgi.framework.util.Headers; -import org.eclipse.osgi.util.ManifestElement; -import org.eclipse.osgi.util.NLS; -import org.osgi.framework.*; - -/** - * An abstract BundleData class that has default implementations that most - * BundleData implementations can use. - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -public abstract class AbstractBundleData implements BundleData, Cloneable { - - /** the Adaptor for this BundleData */ - protected AbstractFrameworkAdaptor adaptor; - - /** - * The Bundle Manifest for this BundleData. - */ - protected Dictionary manifest = null; - - /** - * The Bundle object for this BundleData. - */ - protected Bundle bundle; - - /** bundle id */ - protected long id; - - /** The top level storage directory for the BundleData */ - protected File bundleStoreDir; - - /** The base BundleFile object for this BundleData */ - protected BundleFile baseBundleFile; - ///////////////////// Begin Meta Data for the Bundle ///////////////////// - - /** bundle location */ - private String location; - - /** bundle's file name */ - private String fileName; - - /** native code paths for this BundleData */ - private String[] nativePaths; - - /** bundle generation */ - private int generation = 1; - - /** the bundles start level */ - private int startLevel = -1; - - /** - * The BundleData data directory - */ - protected File dirData; - - /** the bundles status */ - private int status = 0; - - /** Is bundle a reference */ - private boolean reference; - - /** the bundles last modified timestamp */ - private long lastModified; - - ///////////////////// End Meta Data for the Bundle ///////////////////// - - ///////////////////// Begin values from Manifest ///////////////////// - private String symbolicName; - private Version version; - private String activator; - private String classpath; - private String executionEnvironment; - private String dynamicImports; - private int type; - - ///////////////////// End values from Manifest ///////////////////// - - /** - * Constructor for AbstractBundleData - * @param adaptor The adaptor for this bundle data - * @param id The bundle id for this bundle data - */ - public AbstractBundleData(AbstractFrameworkAdaptor adaptor, long id) { - this.adaptor = adaptor; - this.id = id; - initBundleStoreDirs(String.valueOf(id)); - } - - /** - * @see BundleData#getManifest() - */ - public Dictionary getManifest() throws BundleException { - if (manifest == null) { - synchronized (this) { - // make sure the manifest is still null after we have aquired the lock. - if (manifest == null) { - URL url = getEntry(Constants.OSGI_BUNDLE_MANIFEST); - if (url == null) { - throw new BundleException(NLS.bind(AdaptorMsg.MANIFEST_NOT_FOUND_EXCEPTION, Constants.OSGI_BUNDLE_MANIFEST, getLocation())); - } - try { - manifest = Headers.parseManifest(url.openStream()); - } catch (IOException e) { - throw new BundleException(NLS.bind(AdaptorMsg.MANIFEST_NOT_FOUND_EXCEPTION, Constants.OSGI_BUNDLE_MANIFEST, getLocation()), e); - } - } - } - } - return manifest; - } - - /** - * @see BundleData#setBundle(Bundle) - */ - public void setBundle(Bundle bundle) { - this.bundle = bundle; - } - - /** - * Returns the Bundle object for this BundleData. - * @return the Bundle object for this BundleData. - */ - public Bundle getBundle() { - return bundle; - } - - /** - * @see BundleData#getBundleID() - */ - public long getBundleID() { - return (id); - } - - /** - * @see BundleData#getEntry(String) - */ - public URL getEntry(String path) { - BundleEntry entry = getBaseBundleFile().getEntry(path); - if (entry == null) { - return null; - } - if (path.length() == 0 || path.charAt(0) != '/') - path = path = '/' + path; - try { - //use the constant string for the protocol to prevent duplication - return new URL(Constants.OSGI_ENTRY_URL_PROTOCOL, Long.toString(id), 0, path, new Handler(entry)); - } catch (MalformedURLException e) { - return null; - } - } - - /** - * @see BundleData#getEntryPaths(String) - */ - public Enumeration getEntryPaths(String path) { - return getBaseBundleFile().getEntryPaths(path); - } - - /** - * @see BundleData#createClassLoader(ClassLoaderDelegate, BundleProtectionDomain, String[]) - */ - public org.eclipse.osgi.framework.adaptor.BundleClassLoader createClassLoader(ClassLoaderDelegate delegate, BundleProtectionDomain domain, String[] bundleclasspath) { - return getAdaptor().getElementFactory().createClassLoader(delegate, domain, bundleclasspath, this); - } - - /** - * Returns the adaptor for this bundle data. - * @return the adaptor for this bundle data. - */ - public AbstractFrameworkAdaptor getAdaptor() { - return adaptor; - } - - /** - * Returns a list of classpath entries from a list of manifest elements - * @param classpath a list of ManifestElement objects - * @return a list of classpath entries from a list of manifest elements - */ - static String[] getClassPath(ManifestElement[] classpath) { - if (classpath == null) { - if (Debug.DEBUG && Debug.DEBUG_LOADER) - Debug.println(" no classpath"); //$NON-NLS-1$ - /* create default BundleClassPath */ - return new String[] {"."}; //$NON-NLS-1$ - } - - ArrayList result = new ArrayList(classpath.length); - for (int i = 0; i < classpath.length; i++) { - if (Debug.DEBUG && Debug.DEBUG_LOADER) - Debug.println(" found classpath entry " + classpath[i].getValueComponents()); //$NON-NLS-1$ - String[] paths = classpath[i].getValueComponents(); - for (int j = 0; j < paths.length; j++) { - result.add(paths[j]); - } - } - - return (String[]) result.toArray(new String[result.size()]); - } - - ///////////////////// Begin Meta Data Accessor Methods //////////////////// - /** - * @see BundleData#getLocation() - */ - public String getLocation() { - return location; - } - /** - * Sets the location for this bundle data - * @param location the location string - */ - public void setLocation(String location) { - this.location = location; - } - - /** - * Returns the filename for the base file of this bundle data - * @return the filename for the base file of this bundle data - */ - public String getFileName() { - return fileName; - } - - /** - * Sets the filename for the base file of this bundle data - * @param fileName the name of the base file of this bundle data - */ - public void setFileName(String fileName) { - this.fileName = fileName; - } - - /** - * Returns the list of native file paths to install for this bundle - * @return the list of native file paths to install for this bundle - */ - public String[] getNativePaths() { - return nativePaths; - } - - /** - * Returns a comma separated list of native file paths to install for this bundle - * @return a comma separated list of native file paths to install for this bundle - */ - public String getNativePathsString() { - if (nativePaths == null || nativePaths.length == 0) - return null; - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < nativePaths.length; i++) { - sb.append(nativePaths[i]); - if (i < nativePaths.length - 1) - sb.append(','); - } - return sb.toString(); - } - - /** - * Sets the list of native file paths to install for this bundle - * @param nativePaths the list of native file paths to install for this bundle - */ - public void setNativePaths(String[] nativePaths) { - this.nativePaths = nativePaths; - } - - /** - * Sets the comma separated list of native file paths to install for this bundle - * @param nativePaths the comma separated list of native file paths to install for this bundle - */ - public void setNativePaths(String nativePaths) { - if (nativePaths == null) - return; - ArrayList result = new ArrayList(5); - StringTokenizer st = new StringTokenizer(nativePaths, ","); //$NON-NLS-1$ - while (st.hasMoreTokens()) { - String path = st.nextToken(); - result.add(path); - } - setNativePaths((String[]) result.toArray(new String[result.size()])); - } - - /** - * Returns the generation number for this bundle - * @return the generation number for this bundle - */ - public int getGeneration() { - return generation; - } - - /** - * Sets the generation number for this bundle - * @param generation the generation number for this bundle - */ - public void setGeneration(int generation) { - this.generation = generation; - } - - /** - * @see BundleData#getLastModified() - */ - public long getLastModified() { - return lastModified; - } - - /** - * Sets the last modified timestamp for this bundle - * @param lastModified the last modified timestamp for this bundle - */ - public void setLastModified(long lastModified) { - this.lastModified = lastModified; - } - - /** - * @see BundleData#getStartLevel() - */ - public int getStartLevel() { - return startLevel; - } - - /** - * @see BundleData#setStartLevel(int) - */ - public void setStartLevel(int startLevel) { - this.startLevel = startLevel; - } - - /** - * @see BundleData#getStatus() - */ - public int getStatus() { - return status; - } - - /** - * @see BundleData#setStatus(int) - */ - public void setStatus(int status) { - this.status = status; - } - - /** - * Returns if this bundle is installed by reference - * @return true if this bundle is installed by reference - */ - public boolean isReference() { - return reference; - } - - /** - * Sets if this bundle is installed by reference - * @param reference indicates if this bundle is installed by reference - */ - public void setReference(boolean reference) { - this.reference = reference; - } - - ///////////////////// End Meta Data Accessor Methods //////////////////// - - ///////////////////// Begin Manifest Value Accessor Methods ///////////////////// - - /** - * @see BundleData#getSymbolicName() - */ - public String getSymbolicName() { - return symbolicName; - } - - /** - * Returns the base storage directory for this bundle - * @return the base storage directory for this bundle - */ - public File getBundleStoreDir() { - return bundleStoreDir; - } - - /** - * Sets the symbolic name of this bundle - * @param symbolicName the symbolic name of this bundle - */ - public void setSymbolicName(String symbolicName) { - this.symbolicName = symbolicName; - } - - /** - * Loads all metadata for this bundle from the bundle manifest - * @throws BundleException - */ - protected void loadFromManifest() throws BundleException { - getManifest(); - if (manifest == null) - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_ERROR_GETTING_MANIFEST, getLocation())); - try { - setVersion(Version.parseVersion((String) manifest.get(Constants.BUNDLE_VERSION))); - } catch (IllegalArgumentException e) { - setVersion(new InvalidVersion((String) manifest.get(Constants.BUNDLE_VERSION))); - } - ManifestElement[] bsnHeader = ManifestElement.parseHeader(Constants.BUNDLE_SYMBOLICNAME, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME)); - int bundleType = 0; - if (bsnHeader != null) { - setSymbolicName(bsnHeader[0].getValue()); - String singleton = bsnHeader[0].getDirective(Constants.SINGLETON_DIRECTIVE); - if (singleton == null) - singleton = bsnHeader[0].getAttribute(Constants.SINGLETON_DIRECTIVE); - if ("true".equals(singleton)) //$NON-NLS-1$ - bundleType |= TYPE_SINGLETON; - } - setClassPathString((String) manifest.get(Constants.BUNDLE_CLASSPATH)); - setActivator((String) manifest.get(Constants.BUNDLE_ACTIVATOR)); - String host = (String) manifest.get(Constants.FRAGMENT_HOST); - if (host != null) { - bundleType |= TYPE_FRAGMENT; - ManifestElement[] hostElement = ManifestElement.parseHeader(Constants.FRAGMENT_HOST, host); - if (Constants.getInternalSymbolicName().equals(hostElement[0].getValue()) || Constants.OSGI_SYSTEM_BUNDLE.equals(hostElement[0].getValue())) { - String extensionType = hostElement[0].getDirective("extension"); //$NON-NLS-1$ - if (extensionType == null || extensionType.equals("framework")) //$NON-NLS-1$ - bundleType |= TYPE_FRAMEWORK_EXTENSION; - else - bundleType |= TYPE_BOOTCLASSPATH_EXTENSION; - } - } - setType(bundleType); - setExecutionEnvironment((String) manifest.get(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)); - setDynamicImports((String) manifest.get(Constants.DYNAMICIMPORT_PACKAGE)); - } - - /** - * @see BundleData#getVersion() - */ - public Version getVersion() { - return version; - } - - /** - * Sets the version of this bundle - * @param version the version of this bundle - */ - public void setVersion(Version version) { - this.version = version; - } - - /** - * @see BundleData#getActivator() - */ - public String getActivator() { - return activator; - } - - /** - * Returns the data storage directory for this bundle - * @return the data storage directory for this bundle - */ - protected File getDataDir() { - return dirData; - } - - /** - * Sets the bundle store directory for this bundle - * @param bundleStoreDir the store directory for this bundle - */ - protected void setBundleStoreDir(File bundleStoreDir) { - this.bundleStoreDir = bundleStoreDir; - } - - /** - * Sets the initial bundle store directory according to the bundle ID - * @param bundleID the bundle ID - */ - protected void initBundleStoreDirs(String bundleID) { - setBundleStoreDir(new File(((AbstractFrameworkAdaptor) adaptor).getBundleStoreRootDir(), bundleID)); - } - - /** - * Sets the activator for this bundle - * @param activator the activator for this bundle - */ - public void setActivator(String activator) { - this.activator = activator; - } - - /** - * @see BundleData#getClassPath() - */ - public String[] getClassPath() throws BundleException { - ManifestElement[] classpathElements = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, classpath); - return getClassPath(classpathElements); - } - - /** - * Returns the Bundle-ClassPath value as specified in the bundle manifest file. - * @return the Bundle-ClassPath value as specified in the bundle manifest file. - */ - public String getClassPathString() { - return classpath; - } - - /** - * Sets the bundle classpath value of this bundle data. - * @param classpath the bundle classpath - */ - public void setClassPathString(String classpath) { - this.classpath = classpath; - } - - /** - * @see BundleData#getExecutionEnvironment() - */ - public String getExecutionEnvironment() { - return executionEnvironment; - } - - /** - * Sets the execution environment for this bundle - * @param executionEnvironment the execution environment for this bundle - */ - public void setExecutionEnvironment(String executionEnvironment) { - this.executionEnvironment = executionEnvironment; - } - - /** - * @see BundleData#getDynamicImports() - */ - public String getDynamicImports() { - return dynamicImports; - } - - /** - * Sets the dynamic imports of this bundle data. - * @param dynamicImports the dynamic imports - */ - public void setDynamicImports(String dynamicImports) { - this.dynamicImports = dynamicImports; - } - - /** - * @see BundleData#getType() - */ - public int getType() { - return type; - } - - /** - * Sets the type of this bundle - * @param type the type of this bundle - */ - public void setType(int type) { - this.type = type; - } - - ///////////////////// End Manifest Value Accessor Methods ///////////////////// - - /** - * @see BundleData#matchDNChain(String) - */ - public boolean matchDNChain(String pattern) { - if (System.getSecurityManager() == null) - return false; - - if (getBaseBundleFile() instanceof SignedBundle) - return ((SignedBundle) getBaseBundleFile()).matchDNChain(pattern); - return false; - } - - /** - * Return a copy of this object with the - * generation dependent fields updated to - * the next free generation level. - * - * @throws IOException If there are no more available generation levels. - */ - protected AbstractBundleData nextGeneration(String referenceFile) throws IOException { - int nextGeneration = getGeneration(); - - while (nextGeneration < Integer.MAX_VALUE) { - nextGeneration++; - - File nextDirGeneration = new File(getBundleStoreDir(), String.valueOf(nextGeneration)); - - if (nextDirGeneration.exists()) { - continue; - } - - AbstractBundleData next; - try { - next = (AbstractBundleData) clone(); - } catch (CloneNotSupportedException e) { - // this shouldn't happen, since we are Cloneable - throw new InternalError(); - } - - next.setGeneration(nextGeneration); - - if (referenceFile != null) { - next.setReference(true); - next.setFileName(referenceFile); - } else { - if (next.isReference()) { - next.setReference(false); - next.setFileName(AbstractFrameworkAdaptor.BUNDLEFILE_NAME); - } - } - - // null out the manifest to force it to be re-read. - next.manifest = null; - return (next); - } - - throw new IOException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION); - } - - /** - * Initializes a new bundle and loads all its metadata from the bundle manifest - * @throws IOException - * @throws BundleException - */ - public void initializeNewBundle() throws IOException, BundleException { - createBaseBundleFile(); - loadFromManifest(); - } - - /** - * Creates the base BundleFile for this bundle - * @return the base BundleFile for this bundle - * @throws IOException if an IOExceptions occurs - */ - protected BundleFile createBaseBundleFile() throws IOException { - baseBundleFile = getAdaptor().createBaseBundleFile(getBaseFile(), this); - return baseBundleFile; - } - - /** - * Return the base File for the bundle. - * Attempt to create the bundle generation directory if it does not exist. - * - * @return the base File object for the bundle. - */ - protected File getBaseFile() { - return isReference() ? new File(getFileName()) : new File(createGenerationDir(), getFileName()); - } - - /** - * Returns a list of files used for the classpath of this bundle data. - * the contents of the bundle are searched for the classpath entries. - * @param classpaths the classpath entries to search for - * @return a list of files used for the classpath of this bundle data. - */ - protected File[] getClasspathFiles(String[] classpaths) { - ArrayList results = new ArrayList(classpaths.length); - for (int i = 0; i < classpaths.length; i++) { - if (".".equals(classpaths[i])) //$NON-NLS-1$ - results.add(getBaseFile()); - else { - File result = getBaseBundleFile().getFile(classpaths[i]); - if (result != null) - results.add(result); - } - } - return (File[]) results.toArray(new File[results.size()]); - } - - /** - * Sets the data directory for this bundle - * @param dirData the data directory for this bundle - */ - protected void setDataDir(File dirData) { - this.dirData = dirData; - } - - /** - * @see BundleData#findLibrary(String) - */ - public String findLibrary(String libname) { - String mappedName = System.mapLibraryName(libname); - String path = null; - - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println(" mapped library name: " + mappedName); //$NON-NLS-1$ - } - - path = findNativePath(mappedName); - - if (path == null) { - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println(" library does not exist: " + mappedName); //$NON-NLS-1$ - } - path = findNativePath(libname); - } - - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println(" returning library: " + path); //$NON-NLS-1$ - } - return path; - } - - /** - * @see BundleData#open() - */ - public void open() throws IOException { - baseBundleFile.open(); - } - - /** - * Searches the native paths for a match against the specified libname. - * If a match is found then the native path is returned; otherwise a - * <code>null</code> value is returned. - * @param libname a library name - * @return a matching native path or <code>null</code>. - */ - protected String findNativePath(String libname) { - int slash = libname.lastIndexOf('/'); - if (slash >= 0) - libname = libname.substring(slash + 1); - String[] nativepaths = getNativePaths(); - if (nativepaths != null) { - for (int i = 0; i < nativepaths.length; i++) { - slash = nativepaths[i].lastIndexOf('/'); - String path = slash < 0 ? nativePaths[i] : nativePaths[i].substring(slash + 1); - if (path.equals(libname)) { - File nativeFile = baseBundleFile.getFile(nativepaths[i]); - if (nativeFile != null) - return nativeFile.getAbsolutePath(); - } - } - } - return null; - } - - /** - * Return the generation directory for the bundle data. The generation - * directory can be used by the framework to cache files from the bundle - * to the file system. Attempt to create the directory if it does not exist. - * @return The generation directory for the bundle data or null if not - * supported. - */ - public File createGenerationDir() { - File generationDir = getGenerationDir(); - if (!generationDir.exists() && (!adaptor.canWrite() || !generationDir.mkdirs())) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to create bundle generation directory: " + generationDir.getPath()); //$NON-NLS-1$ - } - } - - return generationDir; - } - - /** - * Return the base BundleFile for this BundleData. The base BundleFile - * is the BundleFile that contains all the content of the bundle. - * @return the base BundleFile. - */ - public BundleFile getBaseBundleFile() { - return baseBundleFile; - } - - /** - * Close all resources for this BundleData - */ - public void close() throws IOException { - if (baseBundleFile != null) { - baseBundleFile.close(); - } - } - - /** - * Return the bundle data directory. - * Attempt to create the directory if it does not exist. - * - * @return Bundle data directory. - */ - public File getDataFile(String path) { - // lazily initialize dirData to prevent early access to configuration location - if (getDataDir() == null) { - File dataRoot = adaptor.getDataRootDir(); - if (dataRoot == null) - throw new IllegalStateException(AdaptorMsg.ADAPTOR_DATA_AREA_NOT_SET); - setDataDir(new File(dataRoot, id + "/" + AbstractFrameworkAdaptor.DATA_DIR_NAME)); //$NON-NLS-1$ - } - if (!getDataDir().exists() && (!adaptor.canWrite() || !getDataDir().mkdirs())) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to create bundle data directory: " + getDataDir().getPath()); //$NON-NLS-1$ - } - } - - return (new File(getDataDir(), path)); - } - - /** - * @see BundleData#installNativeCode(String[]) - */ - public void installNativeCode(String[] nativepaths) throws BundleException { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < nativepaths.length; i++) { - // extract the native code - File nativeFile = baseBundleFile.getFile(nativepaths[i]); - if (nativeFile == null) { - throw new BundleException(NLS.bind(AdaptorMsg.BUNDLE_NATIVECODE_EXCEPTION, nativepaths[i])); - } - sb.append(nativepaths[i]); - if (i < nativepaths.length - 1) { - sb.append(","); //$NON-NLS-1$ - } - } - if (sb.length() > 0) - setNativePaths(sb.toString()); - } - - /** - * Returns the generation directory for the bundle data. The returned - * file may not exist. - * @return the generation directory for the bundle data. - */ - protected File getGenerationDir() { - return new File(getBundleStoreDir(), String.valueOf(getGeneration())); - } - - /** - * Returns the parent generation directory for the bundle data. The returned - * file may not exist. A value of <code>null</code> is returned if there is - * no parent generation directory. - * @return the parent gneration directory for the bundle data. - */ - public File getParentGenerationDir() { - return null; - } -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AbstractClassLoader.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AbstractClassLoader.java deleted file mode 100644 index c591f4469..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AbstractClassLoader.java +++ /dev/null @@ -1,219 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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.adaptor.core; - -import java.io.IOException; -import java.net.URL; -import java.security.*; -import java.util.Enumeration; -import org.eclipse.osgi.framework.adaptor.*; -import org.eclipse.osgi.framework.debug.Debug; - -/** - * The AbstractClassLoader provides some basic functionality that all - * BundleClassLoaders must provide. It properly delegates resource and - * class lookups to a parent classloader and the to a ClassLoaderDelegate. - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -public abstract class AbstractClassLoader extends ClassLoader implements BundleClassLoader { - /** - * The delegate used to get classes and resources from. The delegate - * must always be queried first before the local ClassLoader is searched for - * a class or resource. - */ - protected ClassLoaderDelegate delegate; - - /** - * The host ProtectionDomain to use to define classes. - */ - protected ProtectionDomain hostdomain; - - /** - * The host classpath entries for this classloader - */ - protected String[] hostclasspath; - - /** - * BundleClassLoader constructor. - * @param delegate The ClassLoaderDelegate for this bundle. - * @param domain The ProtectionDomain for this bundle. - * @param parent The parent classloader to use. Must not be null. - * @param classpath The classpath entries to use for the host. - */ - public AbstractClassLoader(ClassLoaderDelegate delegate, ProtectionDomain domain, String[] classpath, ClassLoader parent) { - super(parent); - this.delegate = delegate; - this.hostdomain = domain; - this.hostclasspath = classpath; - } - - /** - * Loads a class for the bundle. First delegate.findClass(name) is called. - * The delegate will query the system class loader, bundle imports, bundle - * local classes, bundle hosts and fragments. The delegate will call - * BundleClassLoader.findLocalClass(name) to find a class local to this - * bundle. - * @param name the name of the class to load. - * @param resolve indicates whether to resolve the loaded class or not. - * @return The Class object. - * @throws ClassNotFoundException if the class is not found. - */ - protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - if (Debug.DEBUG && Debug.DEBUG_LOADER) - Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ - try { - // Just ask the delegate. This could result in findLocalClass(name) being called. - Class clazz = delegate.findClass(name); - // resolve the class if asked to. - if (resolve) - resolveClass(clazz); - return (clazz); - } catch (Error e) { - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - Debug.printStackTrace(e); - } - throw e; - } catch (ClassNotFoundException e) { - // If the class is not found do not try to look for it locally. - // The delegate would have already done that for us. - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - Debug.printStackTrace(e); - } - throw e; - } - } - - /** - * Finds a class local to this bundle. The bundle class path is used - * to search for the class. The delegate must not be used. This method - * is abstract to force extending classes to implement this method instead - * of using the ClassLoader.findClass(String) method. - * @param name The classname of the class to find - * @return The Class object. - * @throws ClassNotFoundException if the class is not found. - */ - abstract protected Class findClass(String name) throws ClassNotFoundException; - - /** - * Gets a resource for the bundle. First delegate.findResource(name) is - * called. The delegate will query the system class loader, bundle imports, - * bundle local resources, bundle hosts and fragments. The delegate will - * call BundleClassLoader.findLocalResource(name) to find a resource local - * to this bundle. - * @param name The resource path to get. - * @return The URL of the resource or null if it does not exist. - */ - public URL getResource(String name) { - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println("BundleClassLoader[" + delegate + "].getResource(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - URL url = delegate.findResource(name); - if (url != null) - return (url); - - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println("BundleClassLoader[" + delegate + "].getResource(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - return (null); - } - - /** - * Finds a resource local to this bundle. Simply calls - * findResourceImpl(name) to find the resource. - * @param name The resource path to find. - * @return The URL of the resource or null if it does not exist. - */ - abstract protected URL findResource(String name); - - /** - * Finds all resources with the specified name. This method must call - * delegate.findResources(name) to find all the resources. - * @param name The resource path to find. - * @return An Enumeration of all resources found or null if the resource. - * @throws IOException - */ - protected Enumeration findResources(String name) throws IOException { - return (delegate.findResources(name)); - } - - /** - * Finds a library for this bundle. Simply calls - * delegate.findLibrary(libname) to find the library. - * @param libname The library to find. - * @return The URL of the resource or null if it does not exist. - */ - protected String findLibrary(String libname) { - return delegate.findLibrary(libname); - } - - /** - * Finds a local resource in the BundleClassLoader without - * consulting the delegate. - * @param resource the resource path to find. - * @return a URL to the resource or null if the resource does not exist. - */ - public URL findLocalResource(String resource) { - return findResource(resource); - } - - /** - * Finds a local class in the BundleClassLoader without - * consulting the delegate. - * @param classname the classname to find. - * @return The class object found. - * @throws ClassNotFoundException if the classname does not exist locally. - */ - public Class findLocalClass(String classname) throws ClassNotFoundException { - return findClass(classname); - } - - /** - * Returns a local entry for the specified path - * @param path the entry path - * @return a bundle entry for the specified path or <code>null</code> if the - * path does not exist - */ - // TODO should rename to findLocalEntry ?? - abstract public Object findLocalObject(String path); - - /** - * Returns an Enumeration of local entries for the specified path. The returned - * Enumeration is ordered using the correct local search order of the classpath for - * this classloader. - * @param path the entry path - * @return an enumeration of entries for the specified path or <code>null</code> if - * the path does not exist. - */ - abstract public Enumeration findLocalObjects(String path); - - /** - * @see BundleClassLoader#getDelegate() - */ - public ClassLoaderDelegate getDelegate() { - return delegate; - } - - /** - * @see BundleClassLoader#close() - */ - public void close() { - // do nothing - } - -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AbstractFrameworkAdaptor.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AbstractFrameworkAdaptor.java deleted file mode 100644 index 33cc5c018..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AbstractFrameworkAdaptor.java +++ /dev/null @@ -1,1554 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2006 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.adaptor.core; - -import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLConnection; -import java.util.*; -import org.eclipse.osgi.framework.adaptor.*; -import org.eclipse.osgi.framework.debug.Debug; -import org.eclipse.osgi.framework.internal.core.*; -import org.eclipse.osgi.framework.internal.core.Constants; -import org.eclipse.osgi.framework.log.FrameworkLog; -import org.eclipse.osgi.framework.util.Headers; -import org.eclipse.osgi.service.resolver.*; -import org.eclipse.osgi.util.ManifestElement; -import org.eclipse.osgi.util.NLS; -import org.osgi.framework.*; - -/** - * An abstract FrameworkAdaptor class that has default implementations that most - * FrameworkAdaptor implementations can use. - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -public abstract class AbstractFrameworkAdaptor implements FrameworkAdaptor { - /** - * System property used to set the parent classloader type (boot is the default) - */ - public static final String PROP_PARENT_CLASSLOADER = "osgi.parentClassloader"; //$NON-NLS-1$ - /** - * System property used to specify the list of framework extension bundles - */ - public static final String PROP_FRAMEWORK_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$ - /** - * System property used to specify the bundle singing support class name - */ - public static final String PROP_SIGNINGSUPPORT = "osgi.bundlesigning.support"; //$NON-NLS-1$ - /** - * A parent classloader type that specifies the application classloader - */ - public static final String PARENT_CLASSLOADER_APP = "app"; //$NON-NLS-1$ - /** - * A parent classloader type that specifies the extension classlaoder - */ - public static final String PARENT_CLASSLOADER_EXT = "ext"; //$NON-NLS-1$ - /** - * A parent classloader type that specifies the boot classlaoder - */ - public static final String PARENT_CLASSLOADER_BOOT = "boot"; //$NON-NLS-1$ - /** - * A parent classloader type that specifies the framework classlaoder - */ - public static final String PARENT_CLASSLOADER_FWK = "fwk"; //$NON-NLS-1$ - /** - * The bundle file name used to store bundles into the bundle storage area - */ - public static final String BUNDLEFILE_NAME = "bundlefile"; //$NON-NLS-1$ - - /** - * flag to indicate a framework extension is being intialized - */ - public static final byte EXTENSION_INITIALIZE = 0x01; - /** - * flag to indicate a framework extension is being installed - */ - public static final byte EXTENSION_INSTALLED = 0x02; - /** - * flag to indicate a framework extension is being uninstalled - */ - public static final byte EXTENSION_UNINSTALLED = 0x04; - /** - * flag to indicate a framework extension is being updated - */ - public static final byte EXTENSION_UPDATED = 0x08; - - /** Name of the Adaptor manifest file */ - protected final String ADAPTOR_MANIFEST = "ADAPTOR.MF"; //$NON-NLS-1$ - - /** - * The default bundle signing support class name - */ - protected final String DEFAULT_SIGNEDBUNDLE_SUPPORT = "org.eclipse.osgi.framework.pkcs7verify.SignedBundleSupportImpl"; //$NON-NLS-1$ - - /** - * The EventPublisher for the FrameworkAdaptor - */ - protected EventPublisher eventPublisher; - - /** - * The ServiceRegistry object for this FrameworkAdaptor. - */ - protected ServiceRegistry serviceRegistry; - - /** - * The Properties object for this FrameworkAdaptor - */ - protected Properties properties; - - /** - * The System Bundle's BundleContext. - */ - protected BundleContext context; - - /** - * The initial bundle start level. - */ - protected int initialBundleStartLevel = 1; - - /** This adaptor's manifest file */ - protected Headers manifest = null; - - /** - * Indicates the Framework is stopoing; - * set to true when frameworkStopping(BundleContext) is called - */ - protected boolean stopping = false; - - /** - * The BundleClassLoader parent to use when creating BundleClassLoaders. - * The behavior of the ParentClassLoader will load classes - * from the boot strap classloader. - */ - protected static ClassLoader bundleClassLoaderParent; - /** - * next available bundle id - */ - protected long nextId = 1; - /** - * The State Manager - */ - protected StateManager stateManager; - /** - * directory containing installed bundles - */ - protected File bundleStoreRootDir; - - /** - * The adaptor element factory - */ - protected AdaptorElementFactory elementFactory; - - static { - // check property for specified parent - String type = FrameworkProperties.getProperty(PROP_PARENT_CLASSLOADER, PARENT_CLASSLOADER_BOOT); - if (PARENT_CLASSLOADER_FWK.equalsIgnoreCase(type)) - bundleClassLoaderParent = FrameworkAdaptor.class.getClassLoader(); - else if (PARENT_CLASSLOADER_APP.equalsIgnoreCase(type)) - bundleClassLoaderParent = ClassLoader.getSystemClassLoader(); - else if (PARENT_CLASSLOADER_EXT.equalsIgnoreCase(type)) { - ClassLoader appCL = ClassLoader.getSystemClassLoader(); - if (appCL != null) - bundleClassLoaderParent = appCL.getParent(); - } - - // default to boot classloader - if (bundleClassLoaderParent == null) - bundleClassLoaderParent = new ParentClassLoader(); - } - - /** - * The add URL method used to support framework extensions - */ - protected Method addURLMethod; - - /** - * The list of configured framework extensions - */ - protected String[] configuredExtensions; - - /** - * Indicates if signed bundles are supported - */ - protected boolean supportSignedBundles = true; - /** - * The SingedBundleSupport object. This is set if signed bundles are supported - */ - protected SignedBundleSupport signedBundleSupport = null; - - /** - * Constructor for DefaultAdaptor. This constructor parses the arguments passed - * and remembers them for later when initialize is called. - * <p>No blank spaces should be used in the arguments to the DefaultAdaptor. - * The options that DefaultAdaptor recognizes and handles are: - * <ul> - * <li><b>bundledir=<i>directory name</i></b>If a directory name is specified, the adaptor should initialize - * to store bundles in that directory. This arg should be enclosed in "" if it contains the ":" - * character (example "bundledir=c:\mydir"). - * <li><b>reset</b>Resets the bundle storage by deleting the bundledir - * </ul> - * Any other arguments are ignored. - * - * @param args An array of strings containing arguments. - * This object cannot be used until initialize is called. - * - */ - public AbstractFrameworkAdaptor(String[] args) { - ClassLoader fwloader = AbstractFrameworkAdaptor.class.getClassLoader(); - if (fwloader != null) - addURLMethod = findaddURLMethod(fwloader.getClass()); - if (args != null) { - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (arg.equalsIgnoreCase("reset")) { //$NON-NLS-1$ - reset = true; - } else if (arg.indexOf("=") != -1) { //$NON-NLS-1$ - StringTokenizer tok = new StringTokenizer(args[i], "="); //$NON-NLS-1$ - if (tok.countTokens() == 2) { - String key = tok.nextToken(); - if (key.equalsIgnoreCase("bundledir")) { //$NON-NLS-1$ - // save file name for initializeStorage to use - bundleStore = tok.nextToken(); - } - } - } - } - } - } - - /** - * @see FrameworkAdaptor#initialize(EventPublisher) - */ - public void initialize(EventPublisher eventPublisher) { - this.eventPublisher = eventPublisher; - serviceRegistry = new ServiceRegistryImpl(); - ((ServiceRegistryImpl) serviceRegistry).initialize(); - loadProperties(); - readAdaptorManifest(); - initBundleStoreRootDir(); - // need to create the FrameworkLog very early - frameworkLog = createFrameworkLog(); - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getProperties() - */ - public Properties getProperties() { - return properties; - } - - /** - * Returns the AdaptorElementFactory for this Adaptor. This allows - * extending adaptors to control how BundleData and BundleClassLoader - * objects are created. - * @return the AdaptorElementFactory for this Adapotr. - */ - public abstract AdaptorElementFactory getElementFactory(); - - /** - * Saves the next bundle id to persist storage - * @param value the next bundle id - * @throws IOException - */ - protected abstract void persistNextBundleID(long value) throws IOException; - - /** - * @see FrameworkAdaptor#getFrameworkLog() - */ - public FrameworkLog getFrameworkLog() { - if (frameworkLog == null) - frameworkLog = createFrameworkLog(); - return frameworkLog; - } - - /** - * @see FrameworkAdaptor#getState() - */ - public State getState() { - return stateManager.getSystemState(); - } - - /** - * @see FrameworkAdaptor#getPlatformAdmin() - */ - public PlatformAdmin getPlatformAdmin() { - return stateManager; - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#mapLocationToURLConnection(String) - */ - public URLConnection mapLocationToURLConnection(String location) throws BundleException { - try { - return (new URL(location).openConnection()); - } catch (IOException e) { - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, location), e); - } - } - - /** - * Always returns -1 to indicate that this operation is not supported by this - * FrameworkAdaptor. Extending classes should override this method if - * they support this operation. - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getTotalFreeSpace() - */ - public long getTotalFreeSpace() throws IOException { - return -1; - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getServiceRegistry() - */ - public org.eclipse.osgi.framework.adaptor.ServiceRegistry getServiceRegistry() { - return serviceRegistry; - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#frameworkStart(org.osgi.framework.BundleContext) - */ - public void frameworkStart(BundleContext context) throws BundleException { - this.stopping = false; - this.context = context; - BundleResourceHandler.setContext(context); - if (frameworkLog == null) - frameworkLog = createFrameworkLog(); - if (stateManager == null) - stateManager = createStateManager(); - State state = stateManager.getSystemState(); - checkSystemState(state); - BundleDescription systemBundle = state.getBundle(0); - if (systemBundle == null || !systemBundle.isResolved()) - // this would be a bug in the framework - throw new IllegalStateException(); - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#frameworkStop(org.osgi.framework.BundleContext) - */ - public void frameworkStop(BundleContext context) throws BundleException { - shutdownStateManager(); - this.context = null; - BundleResourceHandler.setContext(null); - frameworkLog.close(); - frameworkLog = null; - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#frameworkStopping(BundleContext) - */ - public void frameworkStopping(BundleContext context) { - this.stopping = true; - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getExportPackages() - */ - public String getExportPackages() { - if (manifest == null) - return null; - return (String) manifest.get(Constants.EXPORT_PACKAGE); - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getExportServices() - */ - public String getExportServices() { - if (manifest == null) - return null; - return (String) manifest.get(Constants.EXPORT_SERVICE); - } - - /** - * @see FrameworkAdaptor#getProvidePackages() - */ - public String getProvidePackages() { - if (manifest == null) - return null; - return (String) manifest.get(Constants.PROVIDE_PACKAGE); - } - - /** - * Returns the EventPublisher for this FrameworkAdaptor. - * @return The EventPublisher. - */ - public EventPublisher getEventPublisher() { - return eventPublisher; - } - - /** - * Indicates if the framework is currently stopping - * @return true if the framework is currently stopping - */ - public boolean isStopping() { - return stopping; - } - - /** - * @see FrameworkAdaptor#getInitialBundleStartLevel() - */ - public int getInitialBundleStartLevel() { - return initialBundleStartLevel; - } - - /** - * @see FrameworkAdaptor#setInitialBundleStartLevel(int) - */ - public void setInitialBundleStartLevel(int value) { - initialBundleStartLevel = value; - } - - /** - * @see FrameworkAdaptor#getBundleWatcher() - */ - public BundleWatcher getBundleWatcher() { - return null; - } - - /** - * The FrameworkLog for the adaptor - */ - protected FrameworkLog frameworkLog; - - public static final String BUNDLE_STORE = "osgi.bundlestore"; //$NON-NLS-1$ - - /** - * This method locates and reads the osgi.properties file. - * If the system property <i>org.eclipse.osgi.framework.internal.core.properties</i> is specifed, its value - * will be used as the name of the file instead of - * <tt>osgi.properties</tt>. There are 3 places to look for these properties. These - * 3 places are searched in the following order, stopping when the properties are found. - * - * <ol> - * <li>Look for a file in the file system - * <li>Look for a resource in the FrameworkAdaptor's package - * </ol> - */ - protected void loadProperties() { - properties = new Properties(); - - String resource = FrameworkProperties.getProperty(Constants.OSGI_PROPERTIES, Constants.DEFAULT_OSGI_PROPERTIES); - - try { - InputStream in = null; - File file = new File(resource); - if (file.exists()) { - in = new FileInputStream(file); - } - - if (in == null) { - in = getClass().getResourceAsStream(resource); - } - - if (in != null) { - try { - properties.load(new BufferedInputStream(in)); - } finally { - try { - in.close(); - } catch (IOException ee) { - } - } - } else { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) - Debug.println("Skipping osgi.properties: " + resource); //$NON-NLS-1$ - } - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to load osgi.properties: " + e.getMessage()); //$NON-NLS-1$ - } - } - - // need to set some OSGi Framework properties that only the adaptor would know about - if (addURLMethod != null) - properties.put(Constants.SUPPORTS_FRAMEWORK_EXTENSION, "true"); //$NON-NLS-1$ - } - - /** - * Return the next valid, unused bundle id. - * - * @return Next valid, unused bundle id. - * @throws IOException If there are no more unused bundle ids. - */ - protected synchronized long getNextBundleId() throws IOException { - while (nextId < Long.MAX_VALUE) { - long id = nextId; - nextId++; - - File bundleDir = new File(getBundleStoreRootDir(), String.valueOf(id)); - if (bundleDir.exists()) { - continue; - } - persistNextBundleID(id); - return (id); - } - - throw new IOException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION); - } - - /** - * Initializes the root bundle data directory - * - */ - protected void initDataRootDir() { - dataRootDir = getBundleStoreRootDir(); - } - - /** - * Reads and initializes the adaptor BundleManifest object. The - * BundleManifest is used by the getExportPackages() and getExportServices() - * methods of the adpator. - */ - protected void readAdaptorManifest() { - InputStream in = null; - // walk up the class hierarchy until we find the ADAPTOR_MANIFEST. - Class adaptorClazz = getClass(); - while (in == null && AbstractFrameworkAdaptor.class.isAssignableFrom(adaptorClazz)) { - in = adaptorClazz.getResourceAsStream(ADAPTOR_MANIFEST); - adaptorClazz = adaptorClazz.getSuperclass(); - } - - if (in == null) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to find adaptor bundle manifest " + ADAPTOR_MANIFEST); //$NON-NLS-1$ - } - manifest = new Headers(new Properties()); - return; - } - try { - manifest = Headers.parseManifest(in); - } catch (BundleException e) { - Debug.println("Unable to read adaptor bundle manifest " + ADAPTOR_MANIFEST); //$NON-NLS-1$ - } - } - - /** - * Creates a framework log - * @return a framework log - */ - abstract protected FrameworkLog createFrameworkLog(); - - /** - * @see FrameworkAdaptor#createSystemBundleData() - */ - public BundleData createSystemBundleData() throws BundleException { - return new SystemBundleData(this); - } - - /** - * Does a recursive copy of one directory to another. - * @param inDir input directory to copy. - * @param outDir output directory to copy to. - * @throws IOException if any error occurs during the copy. - */ - public static void copyDir(File inDir, File outDir) throws IOException { - String[] files = inDir.list(); - if (files != null && files.length > 0) { - outDir.mkdir(); - for (int i = 0; i < files.length; i++) { - File inFile = new File(inDir, files[i]); - File outFile = new File(outDir, files[i]); - if (inFile.isDirectory()) { - copyDir(inFile, outFile); - } else { - InputStream in = new FileInputStream(inFile); - readFile(in, outFile); - } - } - } - } - - /** - * Read a file from an InputStream and write it to the file system. - * - * @param in InputStream from which to read. - * @param file output file to create. - * @exception IOException - */ - public static void readFile(InputStream in, File file) throws IOException { - FileOutputStream fos = null; - try { - fos = new FileOutputStream(file); - - byte buffer[] = new byte[1024]; - int count; - while ((count = in.read(buffer, 0, buffer.length)) > 0) { - fos.write(buffer, 0, count); - } - - fos.close(); - fos = null; - - in.close(); - in = null; - } catch (IOException e) { - // close open streams - if (fos != null) { - try { - fos.close(); - } catch (IOException ee) { - } - } - - if (in != null) { - try { - in.close(); - } catch (IOException ee) { - } - } - - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to read file"); //$NON-NLS-1$ - Debug.printStackTrace(e); - } - - throw e; - } - } - - private static Method findaddURLMethod(Class clazz) { - if (clazz == null) - return null; // ends the recursion when getSuperClass returns null - try { - Method result = clazz.getDeclaredMethod("addURL", new Class[] {URL.class}); //$NON-NLS-1$ - result.setAccessible(true); - return result; - } catch (NoSuchMethodException e) { - // do nothing look in super class below - } catch (SecurityException e) { - // if we do not have the permissions then we will not find the method - } - return findaddURLMethod(clazz.getSuperclass()); - } - - /** - * @see FrameworkAdaptor#getBundleClassLoaderParent() - */ - public ClassLoader getBundleClassLoaderParent() { - return bundleClassLoaderParent; - } - - /** - * Processes an extension bundle - * @param bundleData the extension bundle data - * @param type the type of extension bundle - * @throws BundleException on any errors or if the extension bundle type is not supported - */ - protected void processExtension(BundleData bundleData, byte type) throws BundleException { - if ((bundleData.getType() & BundleData.TYPE_FRAMEWORK_EXTENSION) != 0) { - validateExtension(bundleData); - processFrameworkExtension(bundleData, type); - } else if ((bundleData.getType() & BundleData.TYPE_BOOTCLASSPATH_EXTENSION) != 0) { - validateExtension(bundleData); - processBootExtension(bundleData, type); - } - } - - /** - * Validates the extension bundle metadata - * @param bundleData the extension bundle data - * @throws BundleException if the extension bundle metadata is invalid - */ - protected void validateExtension(BundleData bundleData) throws BundleException { - Dictionary extensionManifest = bundleData.getManifest(); - if (extensionManifest.get(Constants.IMPORT_PACKAGE) != null) - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_EXTENSION_IMPORT_ERROR, bundleData.getLocation())); - if (extensionManifest.get(Constants.REQUIRE_BUNDLE) != null) - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_EXTENSION_REQUIRE_ERROR, bundleData.getLocation())); - if (extensionManifest.get(Constants.BUNDLE_NATIVECODE) != null) - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_EXTENSION_NATIVECODE_ERROR, bundleData.getLocation())); - } - - /** - * Processes a framework extension bundle - * @param bundleData the extension bundle data - * @param type the type of extension bundle - * @throws BundleException on errors or if framework extensions are not supported - */ - protected void processFrameworkExtension(BundleData bundleData, byte type) throws BundleException { - if (addURLMethod == null) - throw new BundleException("Framework extensions are not supported.", new UnsupportedOperationException()); //$NON-NLS-1$ - if ((type & (EXTENSION_UNINSTALLED | EXTENSION_UPDATED)) != 0) - // if uninstalled or updated then do nothing framework must be restarted. - return; - - // first make sure this BundleData is not on the pre-configured osgi.framework.extensions list - String[] extensions = getConfiguredExtensions(); - for (int i = 0; i < extensions.length; i++) - if (extensions[i].equals(bundleData.getSymbolicName())) - return; - File[] files = getExtensionFiles(bundleData); - if (files == null) - return; - for (int i = 0; i < files.length; i++) { - if (files[i] == null) - continue; - Throwable exceptionLog = null; - try { - addURLMethod.invoke(getClass().getClassLoader(), new Object[] {files[i].toURL()}); - } catch (InvocationTargetException e) { - exceptionLog = e.getTargetException(); - } catch (Throwable t) { - exceptionLog = t; - } finally { - if (exceptionLog != null) - eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, ((AbstractBundleData) bundleData).getBundle(), exceptionLog); - } - } - } - - /** - * Returns a list of configured extensions - * @return a list of configured extensions - */ - protected String[] getConfiguredExtensions() { - if (configuredExtensions != null) - return configuredExtensions; - String prop = FrameworkProperties.getProperty(PROP_FRAMEWORK_EXTENSIONS); - if (prop == null || prop.trim().length() == 0) - configuredExtensions = new String[0]; - else - configuredExtensions = ManifestElement.getArrayFromList(prop); - return configuredExtensions; - } - - /** - * Processes a boot extension bundle - * @param bundleData the extension bundle data - * @param type the type of extension bundle - * @throws BundleException on errors or if boot extensions are not supported - */ - protected void processBootExtension(BundleData bundleData, byte type) throws BundleException { - throw new BundleException("Boot classpath extensions are not supported.", new UnsupportedOperationException()); //$NON-NLS-1$ - } - - /** - * Returns a list of classpath files for an extension bundle - * @param bundleData the bundle data for an extension bundle - * @return a list of classpath files for an extension bundle - */ - protected File[] getExtensionFiles(BundleData bundleData) { - File[] files = null; - try { - String[] paths = bundleData.getClassPath(); - // TODO need to be smarter about dev path here - if (FrameworkProperties.getProperty("osgi.dev") != null) { //$NON-NLS-1$ - String[] origPaths = paths; - paths = new String[origPaths.length + 1]; - System.arraycopy(origPaths, 0, paths, 0, origPaths.length); - paths[paths.length - 1] = "bin"; //$NON-NLS-1$ - } - files = ((AbstractBundleData) bundleData).getClasspathFiles(paths); - } catch (BundleException e) { - eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, ((AbstractBundleData) bundleData).getBundle(), e); - } - return files; - } - - /** - * @see FrameworkAdaptor#handleRuntimeError(Throwable) - */ - public void handleRuntimeError(Throwable error) { - // do nothing by default. - } - - /** - * Returns the root data directory - * @return the root data directory - */ - public File getDataRootDir() { - if (dataRootDir == null) - initDataRootDir(); - return dataRootDir; - } - - /** - * Creates a BundleFile object from a File object and a BundleData - * object. This implementation checks to see if the basefile is - * a directory or a regular file and creates the proper BundleFile - * type accordingly. If the file is a regular file this implementation - * assumes that the file is a zip file. - * @param basefile the base File object. - * @param bundledata the BundleData object that BundleFile is associated with. - * @return A new BundleFile object - * @throws IOException if an error occurred creating the BundleFile object. - */ - public BundleFile createBundleFile(File basefile, BundleData bundledata) throws IOException { - if (basefile.isDirectory()) - return new BundleFile.DirBundleFile(basefile); - return new BundleFile.ZipBundleFile(basefile, bundledata); - } - - /** - * Creates a base bundle file for a bundle - * @param basefile the base file object for the bundle - * @param bundledata the bundle data for the bundle - * @return a base bundle file for a bundle - * @throws IOException - */ - public BundleFile createBaseBundleFile(File basefile, BundleData bundledata) throws IOException { - BundleFile base = createBundleFile(basefile, bundledata); - if (System.getSecurityManager() == null || !supportSignedBundles) - return base; - SignedBundleSupport support = getSignedBundleSupport(); - if (support == null) - return base; - SignedBundle signedBundle = support.createSignedBundle(); - signedBundle.setBundleFile(base); - return signedBundle; - } - - /** - * @see FrameworkAdaptor#matchDNChain(String, String[]) - */ - public boolean matchDNChain(String pattern, String[] dnChain) { - SignedBundleSupport support = getSignedBundleSupport(); - if (support != null) - return support.matchDNChain(pattern, dnChain); - return false; - } - - /** - * Returns the SignedBundleSupport object. If signed bundles are not - * supported then <code>null</code> is returned. - * @return the SignedBundleSupport object or <code>null</code> if signed bundles - * are not supported. - */ - protected SignedBundleSupport getSignedBundleSupport() { - if (System.getSecurityManager() == null || !supportSignedBundles) - return null; - try { - if (signedBundleSupport == null) { - String clazzName = FrameworkProperties.getProperty(PROP_SIGNINGSUPPORT, DEFAULT_SIGNEDBUNDLE_SUPPORT); - Class clazz = Class.forName(clazzName); - signedBundleSupport = (SignedBundleSupport) clazz.newInstance(); - } - return signedBundleSupport; - } catch (ClassNotFoundException e) { - supportSignedBundles = false; - } catch (IllegalAccessException e) { - supportSignedBundles = false; - } catch (InstantiationException e) { - supportSignedBundles = false; - } - return null; - } - - /** - * @see FrameworkAdaptor#installBundle(String, URLConnection) - */ - public BundleOperation installBundle(final String location, final URLConnection source) { - return (new BundleOperation() { - private AbstractBundleData data; - - /** - * Begin the operation on the bundle (install, update, uninstall). - * - * @return BundleData object for the target bundle. - * @throws BundleException If a failure occured modifiying peristent storage. - */ - public org.eclipse.osgi.framework.adaptor.BundleData begin() throws BundleException { - long id; - - try { - /* - * Open InputStream first to trigger prereq installs, if any, - * before allocating bundle id. - */ - InputStream in = source.getInputStream(); - URL sourceURL = source.getURL(); - String protocol = sourceURL == null ? null : sourceURL.getProtocol(); - try { - try { - id = getNextBundleId(); - } catch (IOException e) { - throw new BundleException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION, e); - } - data = getElementFactory().createBundleData(AbstractFrameworkAdaptor.this, id); - data.setLastModified(System.currentTimeMillis()); - data.setLocation(location); - data.setStartLevel(getInitialBundleStartLevel()); - - if (in instanceof ReferenceInputStream) { - URL reference = ((ReferenceInputStream) in).getReference(); - - if (!"file".equals(reference.getProtocol())) { //$NON-NLS-1$ - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, reference)); - } - - data.setReference(true); - data.setFileName(reference.getPath()); - data.initializeNewBundle(); - } else { - File genDir = data.createGenerationDir(); - if (!genDir.exists()) { - throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, genDir.getPath())); - } - - String fileName = BUNDLEFILE_NAME; - File outFile = new File(genDir, fileName); - if ("file".equals(protocol)) { //$NON-NLS-1$ - File inFile = new File(source.getURL().getPath()); - if (inFile.isDirectory()) { - copyDir(inFile, outFile); - } else { - readFile(in, outFile); - } - } else { - readFile(in, outFile); - } - data.setReference(false); - data.setFileName(fileName); - data.initializeNewBundle(); - } - } finally { - try { - in.close(); - } catch (IOException e) { - } - } - } catch (IOException ioe) { - throw new BundleException(AdaptorMsg.BUNDLE_READ_EXCEPTION, ioe); - } - - return (data); - } - - public void undo() { - if (data != null) { - try { - data.close(); - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to close " + data + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - } - - if (data != null) { - File bundleDir = data.getBundleStoreDir(); - - if (!rm(bundleDir)) { - /* mark this bundle to be deleted to ensure it is fully cleaned up - * on next restart. - */ - File delete = new File(bundleDir, ".delete"); //$NON-NLS-1$ - - if (!delete.exists()) { - try { - /* create .delete */ - FileOutputStream out = new FileOutputStream(delete); - out.close(); - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - } - } - } - } - - public void commit(boolean postpone) throws BundleException { - processExtension(data, EXTENSION_INSTALLED); - try { - data.save(); - } catch (IOException e) { - throw new BundleException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION, e); - } - updateState(data, BundleEvent.INSTALLED); - } - - }); - } - - /** - * This function performs the equivalent of "rm -r" on a file or directory. - * - * @param file file or directory to delete - * @return false is the specified files still exists, true otherwise. - */ - protected boolean rm(File file) { - if (file.exists()) { - if (file.isDirectory()) { - String list[] = file.list(); - if (list != null) { - int len = list.length; - for (int i = 0; i < len; i++) { - // we are doing a lot of garbage collecting here - rm(new File(file, list[i])); - } - } - } - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - if (file.isDirectory()) { - Debug.println("rmdir " + file.getPath()); //$NON-NLS-1$ - } else { - Debug.println("rm " + file.getPath()); //$NON-NLS-1$ - } - } - - boolean success = file.delete(); - - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - if (!success) { - Debug.println(" rm failed!!"); //$NON-NLS-1$ - } - } - - return (success); - } - return (true); - } - - /** - * Shutdown the StateManager for the adaptor. This should persist the state - * for reading when createStateManager is called. - */ - protected void shutdownStateManager() { - try { - if (canWrite() && (getBundleStoreRootDir().exists() || getBundleStoreRootDir().mkdirs())) - stateManager.shutdown(new File(getBundleStoreRootDir(), ".state"), new File(getBundleStoreRootDir(), ".lazy")); //$NON-NLS-1$//$NON-NLS-2$ - } catch (IOException e) { - frameworkLog.log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e)); - } finally { - stateManager = null; - } - } - - /** - * Returns the bundle store root directory - * @return the bundle store root directory - */ - public File getBundleStoreRootDir() { - return bundleStoreRootDir; - } - - /** - * String containing bundle store root dir - */ - protected String bundleStore = null; - /** - * Dictionary containing permission data - */ - protected PermissionStorage permissionStore; - /** - * inidicates that the bundle storage should be reset - */ - protected boolean reset = false; - /** - * directory containing data directories for installed bundles - */ - protected File dataRootDir; - /** - * The name of the bundle data directory - */ - public static final String DATA_DIR_NAME = "data";//$NON-NLS-1$ - /** - * Indicates that the state has become invalid as a result of - * installing/updating/uninstalling a bundle before the state mananger is - * created - */ - protected boolean invalidState = false; - - /** - * @see FrameworkAdaptor#updateBundle(BundleData, URLConnection) - */ - public BundleOperation updateBundle(final org.eclipse.osgi.framework.adaptor.BundleData bundledata, final URLConnection source) { - return (new BundleOperation() { - private AbstractBundleData data; - private AbstractBundleData newData; - - /** - * Perform the change to persistent storage. - * - * @return Bundle object for the target bundle. - */ - public org.eclipse.osgi.framework.adaptor.BundleData begin() throws BundleException { - this.data = (AbstractBundleData) bundledata; - try { - InputStream in = source.getInputStream(); - URL sourceURL = source.getURL(); - String protocol = sourceURL == null ? null : sourceURL.getProtocol(); - try { - if (in instanceof ReferenceInputStream) { - ReferenceInputStream refIn = (ReferenceInputStream) in; - URL reference = (refIn).getReference(); - if (!"file".equals(reference.getProtocol())) { //$NON-NLS-1$ - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, reference)); - } - // check to make sure we are not just trying to update to the same - // directory reference. This would be a no-op. - String path = reference.getPath(); - if (path.equals(data.getFileName())) { - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_SAME_REF_UPDATE, reference)); - } - try { - newData = data.nextGeneration(reference.getPath()); - } catch (IOException e) { - throw new BundleException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION, e); - } - File bundleGenerationDir = newData.createGenerationDir(); - if (!bundleGenerationDir.exists()) { - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, bundleGenerationDir.getPath())); - } - newData.createBaseBundleFile(); - } else { - try { - newData = data.nextGeneration(null); - } catch (IOException e) { - throw new BundleException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION, e); - } - File bundleGenerationDir = newData.createGenerationDir(); - if (!bundleGenerationDir.exists()) { - throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, bundleGenerationDir.getPath())); - } - File outFile = newData.getBaseFile(); - if ("file".equals(protocol)) { //$NON-NLS-1$ - File inFile = new File(source.getURL().getPath()); - if (inFile.isDirectory()) { - copyDir(inFile, outFile); - } else { - readFile(in, outFile); - } - } else { - readFile(in, outFile); - } - newData.createBaseBundleFile(); - } - } finally { - try { - in.close(); - } catch (IOException ee) { - } - } - newData.loadFromManifest(); - } catch (IOException e) { - throw new BundleException(AdaptorMsg.BUNDLE_READ_EXCEPTION, e); - } - - return (newData); - } - - /** - * Commit the change to persistent storage. - * - * @param postpone If true, the bundle's persistent - * storage cannot be immediately reclaimed. - * @throws BundleException If a failure occured modifiying peristent storage. - */ - - public void commit(boolean postpone) throws BundleException { - processExtension(data, EXTENSION_UNINSTALLED); // remove the old extension - processExtension(newData, EXTENSION_UPDATED); // update to the new one - try { - newData.setLastModified(System.currentTimeMillis()); - newData.save(); - } catch (IOException e) { - throw new BundleException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION, e); - } - updateState(newData, BundleEvent.UPDATED); - File originalGenerationDir = data.createGenerationDir(); - - if (postpone || !rm(originalGenerationDir)) { - /* mark this bundle to be deleted to ensure it is fully cleaned up - * on next restart. - */ - File delete = new File(originalGenerationDir, ".delete"); //$NON-NLS-1$ - - if (!delete.exists()) { - try { - /* create .delete */ - FileOutputStream out = new FileOutputStream(delete); - out.close(); - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ - } - - eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, data.getBundle(), e); - } - } - } - } - - /** - * Undo the change to persistent storage. - * - * @throws BundleException If a failure occured modifiying peristent storage. - */ - public void undo() throws BundleException { - /*if (bundleFile != null) - { - bundleFile.close(); - } */ - - if (newData != null) { - File nextGenerationDir = newData.createGenerationDir(); - - if (!rm(nextGenerationDir)) /* delete downloaded bundle */{ - /* mark this bundle to be deleted to ensure it is fully cleaned up - * on next restart. - */ - File delete = new File(nextGenerationDir, ".delete"); //$NON-NLS-1$ - - if (!delete.exists()) { - try { - /* create .delete */ - FileOutputStream out = new FileOutputStream(delete); - out.close(); - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - } - } - } - } - }); - } - - /** - * Iterates over the bundles in a state and removes any bundles in state that - * do not exist in the framework - * @param state the state to check - */ - protected void checkSystemState(State state) { - BundleDescription[] bundles = state.getBundles(); - if (bundles == null) - return; - boolean removedBundle = false; - for (int i = 0; i < bundles.length; i++) { - if (context.getBundle(bundles[i].getBundleId()) == null) { - state.removeBundle(bundles[i]); - removedBundle = true; - } - } - if (removedBundle) - state.resolve(false); // do a full resolve - } - - /** - * Creates the StateManager for the adaptor - * @return the StateManager. - */ - protected StateManager createStateManager() { - stateManager = new StateManager(new File(getBundleStoreRootDir(), ".state"), new File(getBundleStoreRootDir(), ".lazy"), context); //$NON-NLS-1$ //$NON-NLS-2$ - State systemState = null; - if (!invalidState) { - systemState = stateManager.readSystemState(); - if (systemState != null) - return stateManager; - } - systemState = stateManager.createSystemState(); - Bundle[] installedBundles = context.getBundles(); - if (installedBundles == null) - return stateManager; - StateObjectFactory factory = stateManager.getFactory(); - for (int i = 0; i < installedBundles.length; i++) { - Bundle toAdd = installedBundles[i]; - try { - Dictionary manifest = toAdd.getHeaders(""); //$NON-NLS-1$ - BundleDescription newDescription = factory.createBundleDescription(systemState, manifest, toAdd.getLocation(), toAdd.getBundleId()); - systemState.addBundle(newDescription); - } catch (BundleException be) { - // just ignore bundle datas with invalid manifests - } - } - // we need the state resolved - systemState.resolve(); - invalidState = false; - return stateManager; - } - - /** - * @see FrameworkAdaptor#uninstallBundle(BundleData) - */ - public BundleOperation uninstallBundle(final org.eclipse.osgi.framework.adaptor.BundleData bundledata) { - return (new BundleOperation() { - private AbstractBundleData data; - - /** - * Perform the change to persistent storage. - * - * @return Bundle object for the target bundle. - * @throws BundleException If a failure occured modifiying peristent storage. - */ - public org.eclipse.osgi.framework.adaptor.BundleData begin() throws BundleException { - this.data = (AbstractBundleData) bundledata; - return (bundledata); - } - - /** - * Commit the change to persistent storage. - * - * @param postpone If true, the bundle's persistent - * storage cannot be immediately reclaimed. - * @throws BundleException If a failure occured modifiying peristent storage. - */ - public void commit(boolean postpone) throws BundleException { - File bundleDir = data.getBundleStoreDir(); - - if (postpone || !rm(bundleDir)) { - /* mark this bundle to be deleted to ensure it is fully cleaned up - * on next restart. - */ - - File delete = new File(bundleDir, ".delete"); //$NON-NLS-1$ - - if (!delete.exists()) { - try { - /* create .delete */ - FileOutputStream out = new FileOutputStream(delete); - out.close(); - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - } - } - - processExtension(data, EXTENSION_UNINSTALLED); - data.setLastModified(System.currentTimeMillis()); - updateState(data, BundleEvent.UNINSTALLED); - } - - /** - * Undo the change to persistent storage. - * - * @throws BundleException If a failure occured modifiying peristent storage. - */ - public void undo() throws BundleException { - } - }); - } - - /** - * Init the directory to store the bundles in. Bundledir can be set in 3 different ways. - * Priority is: - * 1 - OSGI Launcher command line -adaptor argument - * 2 - System property osgi.bundlestore - could be specified with -D when launching - * 3 - osgi.properties - osgi.bundlestore property - * - * Bundledir will be stored back to adaptor properties which - * the framework will copy into the System properties. - */ - protected void initBundleStoreRootDir() { - /* if bundleStore was not set by the constructor from the -adaptor cmd line arg */ - if (bundleStore == null) { - /* check the system properties */ - bundleStore = FrameworkProperties.getProperty(BUNDLE_STORE); - - if (bundleStore == null) { - /* check the osgi.properties file, but default to "bundles" */ - bundleStore = properties.getProperty(BUNDLE_STORE, "bundles"); //$NON-NLS-1$ - } - } - - bundleStoreRootDir = new File(bundleStore); - /* store bundleStore back into adaptor properties for others to see */ - properties.put(BUNDLE_STORE, bundleStoreRootDir.getAbsolutePath()); - - } - - /** - * Register a service object. - * @param name the service class name - * @param service the service object - * @param bundle the registering bundle - * @return the service registration object - */ - protected ServiceRegistration register(String name, Object service, Bundle bundle) { - Hashtable properties = new Hashtable(7); - - Dictionary headers = bundle.getHeaders(); - - properties.put(Constants.SERVICE_VENDOR, headers.get(Constants.BUNDLE_VENDOR)); - - properties.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE)); - - properties.put(Constants.SERVICE_PID, bundle.getBundleId() + "." + service.getClass().getName()); //$NON-NLS-1$ - - return context.registerService(name, service, properties); - } - - /** - * Initialize the persistent storage. - * - * <p>This method initializes the bundle persistent storage - * area. - * If a dir was specified in the -adaptor command line option, then it - * is used. If not, - * if the property - * <i>osgi.bundlestore</i> is specified, its value - * will be used as the name of the bundle directory - * instead of <tt>./bundles</tt>. - * If reset was specified on the -adaptor command line option, - * then the storage will be cleared. - * - * @throws IOException If an error occurs initializing the storage. - */ - public void initializeStorage() throws IOException { - File bundleStore; - // only touch the file system if reset is specified - // we create the area on demand later if needed - if (reset && (bundleStore = getBundleStoreRootDir()).exists()) { - if (!canWrite() || !rm(bundleStore)) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Could not remove directory: " + bundleStore.getPath()); //$NON-NLS-1$ - } - - throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_REMOVE_EXCEPTION, bundleStore)); - } - } - - initializeMetadata(); - } - - /** - * Initialize the metadata for the adaptor - * @throws IOException - */ - abstract protected void initializeMetadata() throws IOException; - - /** - * @see FrameworkAdaptor#getPermissionStorage() - */ - public org.eclipse.osgi.framework.adaptor.PermissionStorage getPermissionStorage() throws IOException { - if (permissionStore == null) { - synchronized (this) { - if (permissionStore == null) { - permissionStore = new DefaultPermissionStorage(this); - } - } - } - - return permissionStore; - } - - /** - * @see FrameworkAdaptor#compactStorage() - */ - public void compactStorage() { - if (canWrite()) - compact(getBundleStoreRootDir()); - } - - /** - * This method cleans up storage in the specified directory and - * any subdirectories. - * - * @param directory The directory to clean. - * @see #compactStorage - */ - private void compact(File directory) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("compact(" + directory.getPath() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - String list[] = directory.list(); - if (list == null) - return; - - int len = list.length; - - for (int i = 0; i < len; i++) { - if (DATA_DIR_NAME.equals(list[i])) { - continue; /* do not examine the bundles data dir. */ - } - - File target = new File(directory, list[i]); - - /* if the file is a directory */ - if (!target.isDirectory()) - continue; - File delete = new File(target, ".delete"); //$NON-NLS-1$ - - /* and the directory is marked for delete */ - if (delete.exists()) { - /* if rm fails to delete the directory * - * and .delete was removed - */ - if (!rm(target) && !delete.exists()) { - try { - /* recreate .delete */ - FileOutputStream out = new FileOutputStream(delete); - out.close(); - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - } - } else { - compact(target); /* descend into directory */ - } - } - } - - /** - * Returns the metadata file for the adaptor - * @return the metadata file for the adaptor - */ - protected File getMetaDataFile() { - return new File(getBundleStoreRootDir(), ".framework"); //$NON-NLS-1$ - } - - /** - * Empty parent classloader. This is used by default as the BundleClassLoader - * parent. - */ - protected static class ParentClassLoader extends ClassLoader { - protected ParentClassLoader() { - super(null); - } - } - - /** - * Updates the state mananager with an updated/installed/uninstalled bundle - * @param bundleData the modified bundle - * @param type the type of modification - * @throws BundleException - */ - protected void updateState(BundleData bundleData, int type) throws BundleException { - if (stateManager == null) { - invalidState = true; - return; - } - State systemState = stateManager.getSystemState(); - switch (type) { - case BundleEvent.UPDATED : - systemState.removeBundle(bundleData.getBundleID()); - // fall through to INSTALLED - case BundleEvent.INSTALLED : - BundleDescription newDescription = stateManager.getFactory().createBundleDescription(systemState, bundleData.getManifest(), bundleData.getLocation(), bundleData.getBundleID()); - systemState.addBundle(newDescription); - break; - case BundleEvent.UNINSTALLED : - systemState.removeBundle(bundleData.getBundleID()); - break; - } - } - - /** - * Whether the adaptor can make changes to the file system. Default is <code>true</code>. - */ - public boolean canWrite() { - return true; - } -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AdaptorElementFactory.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AdaptorElementFactory.java deleted file mode 100644 index a3abb5c18..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AdaptorElementFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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.adaptor.core; - -import java.io.IOException; -import org.eclipse.osgi.framework.adaptor.BundleClassLoader; -import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain; -import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; - -/** - * This interface allows extending adaptors to control how BundleData and BundleClassLoader - * objects are created. - * <p> - * Clients may implement this interface. - * </p> - * @since 3.1 - */ -public interface AdaptorElementFactory { - /** - * Creates a bundle data object for a bundle - * @param adaptor the adaptor creating the bundle data for - * @param id the bundle ID to use for the constructed bundle data object - * @return a bundle data object for a bundle - * @throws IOException - */ - public AbstractBundleData createBundleData(AbstractFrameworkAdaptor adaptor, long id) throws IOException; - - /** - * Creates a bundle classloader for a bundle - * @param delegate the classloader delegate - * @param domain the classloader domain - * @param bundleclasspath the classloader classapth - * @param data the classloader bundle data - * @return a bundle classloader for a bundle - */ - public BundleClassLoader createClassLoader(ClassLoaderDelegate delegate, BundleProtectionDomain domain, String[] bundleclasspath, AbstractBundleData data); - -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/BundleEntry.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/BundleEntry.java deleted file mode 100644 index 926ecd1a7..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/BundleEntry.java +++ /dev/null @@ -1,298 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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.adaptor.core; - -import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.zip.ZipEntry; - -/** - * A BundleEntry represents one entry of a BundleFile. - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -public abstract class BundleEntry { - /** - * Return an InputStream for the entry. - * - * @return InputStream for the entry. - * @throws java.io.IOException If an error occurs reading the bundle. - */ - public abstract InputStream getInputStream() throws IOException; - - /** - * Return the size of the entry (uncompressed). - * - * @return size of entry. - */ - public abstract long getSize(); - - /** - * Return the name of the entry. - * - * @return name of entry. - */ - public abstract String getName(); - - /** - * Get the modification time for this BundleEntry. - * <p>If the modification time has not been set, - * this method will return <tt>-1</tt>. - * - * @return last modification time. - */ - public abstract long getTime(); - - /** - * Get a URL to the bundle entry that uses a common protocol (i.e. file: - * jar: or http: etc.). - * @return a URL to the bundle entry that uses a common protocol - */ - public abstract URL getLocalURL(); - - /** - * Get a URL to the content of the bundle entry that uses the file: protocol. - * The content of the bundle entry may be downloaded or extracted to the local - * file system in order to create a file: URL. - * @return a URL to the content of the bundle entry that uses the file: protocol - */ - public abstract URL getFileURL(); - - /** - * Return the name of this BundleEntry by calling getName(). - * - * @return String representation of this BundleEntry. - */ - public String toString() { - return (getName()); - } - - /** - * A BundleEntry represented by a ZipEntry in a ZipFile. The ZipBundleEntry - * class is used for bundles that are installed as a ZipFile on a file system. - */ - public static class ZipBundleEntry extends BundleEntry { - /** - * ZipEntry for this entry. - */ - protected ZipEntry zipEntry; - - /** - * The BundleFile for this entry. - */ - protected BundleFile bundleFile; - - /** - * Constructs the BundleEntry using a ZipEntry. - * @param bundleFile BundleFile object this entry is a member of - * @param entry ZipEntry object of this entry - */ - protected ZipBundleEntry(ZipEntry entry, BundleFile bundleFile) { - this.zipEntry = entry; - this.bundleFile = bundleFile; - } - - /** - * Return an InputStream for the entry. - * - * @return InputStream for the entry - * @exception java.io.IOException - */ - public InputStream getInputStream() throws IOException { - return ((BundleFile.ZipBundleFile) bundleFile).getZipFile().getInputStream(zipEntry); - } - - /** - * Return size of the uncompressed entry. - * - * @return size of entry - */ - public long getSize() { - return zipEntry.getSize(); - } - - /** - * Return name of the entry. - * - * @return name of entry - */ - public String getName() { - return zipEntry.getName(); - } - - /** - * Get the modification time for this BundleEntry. - * <p>If the modification time has not been set, - * this method will return <tt>-1</tt>. - * - * @return last modification time. - */ - public long getTime() { - return zipEntry.getTime(); - } - - public URL getLocalURL() { - try { - return new URL("jar:file:" + bundleFile.basefile.getAbsolutePath() + "!/" + zipEntry.getName()); //$NON-NLS-1$//$NON-NLS-2$ - } catch (MalformedURLException e) { - //This can not happen. - return null; - } - } - - public URL getFileURL() { - try { - File file = bundleFile.getFile(zipEntry.getName()); - if (file != null) - return file.toURL(); - } catch (MalformedURLException e) { - //This can not happen. - } - return null; - } - } - - /** - * A BundleEntry represented by a File object. The FileBundleEntry class is - * used for bundles that are installed as extracted zips on a file system. - */ - public static class FileBundleEntry extends BundleEntry { - /** - * File for this entry. - */ - private File file; - /** - * The name for this entry - */ - private String name; - - /** - * Constructs the BundleEntry using a File. - * @param file BundleFile object this entry is a member of - * @param name the name of this BundleEntry - */ - FileBundleEntry(File file, String name) { - this.file = file; - this.name = name; - } - - /** - * Return an InputStream for the entry. - * - * @return InputStream for the entry - * @exception java.io.IOException - */ - public InputStream getInputStream() throws IOException { - return BundleFile.secureAction.getFileInputStream(file); - } - - /** - * Return size of the uncompressed entry. - * - * @return size of entry - */ - public long getSize() { - return BundleFile.secureAction.length(file); - } - - /** - * Return name of the entry. - * - * @return name of entry - */ - public String getName() { - return (name); - } - - /** - * Get the modification time for this BundleEntry. - * <p>If the modification time has not been set, - * this method will return <tt>-1</tt>. - * - * @return last modification time. - */ - public long getTime() { - return BundleFile.secureAction.lastModified(file); - } - - public URL getLocalURL() { - return getFileURL(); - } - - public URL getFileURL() { - try { - return file.toURL(); - } catch (MalformedURLException e) { - return null; - } - } - } - - /** - * Represents a directory entry in a ZipBundleFile. This object is used to - * reference a directory entry in a ZipBundleFile when the directory entries are - * not included in the zip file. - */ - public static class DirZipBundleEntry extends BundleEntry { - - /** - * ZipBundleFile for this entry. - */ - private BundleFile.ZipBundleFile bundleFile; - /** - * The name for this entry - */ - private String name; - - public DirZipBundleEntry(BundleFile.ZipBundleFile bundleFile, String name) { - this.name = (name.length() > 0 && name.charAt(0) == '/') ? name.substring(1) : name; - this.bundleFile = bundleFile; - } - - public InputStream getInputStream() throws IOException { - return null; - } - - public long getSize() { - return 0; - } - - public String getName() { - return name; - } - - public long getTime() { - return 0; - } - - public URL getLocalURL() { - try { - return new URL("jar:file:" + bundleFile.basefile.getAbsolutePath() + "!/" + name); //$NON-NLS-1$ //$NON-NLS-2$ - } catch (MalformedURLException e) { - //This can not happen, unless the jar protocol is not supported. - return null; - } - } - - public URL getFileURL() { - try { - return bundleFile.extractDirectory(name).toURL(); - } catch (MalformedURLException e) { - // this cannot happen. - return null; - } - } - } -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/BundleFile.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/BundleFile.java deleted file mode 100644 index 1365523a4..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/BundleFile.java +++ /dev/null @@ -1,597 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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.adaptor.core; - -import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.*; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import org.eclipse.osgi.framework.adaptor.BundleData; -import org.eclipse.osgi.framework.debug.Debug; -import org.eclipse.osgi.framework.internal.core.Constants; -import org.eclipse.osgi.framework.internal.protocol.bundleresource.Handler; -import org.eclipse.osgi.framework.util.SecureAction; -import org.eclipse.osgi.util.NLS; -import org.osgi.framework.FrameworkEvent; - -/** - * The BundleFile API is used by Adaptors to read resources out of an - * installed Bundle in the Framework. - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -abstract public class BundleFile { - static final SecureAction secureAction = new SecureAction(); - /** - * The File object for this BundleFile. - */ - protected File basefile; - - /** - * Default constructor - * - */ - public BundleFile() { - // do nothing - } - - /** - * BundleFile constructor - * @param basefile The File object where this BundleFile is - * persistently stored. - */ - public BundleFile(File basefile) { - this.basefile = basefile; - } - - /** - * Returns a File for the bundle entry specified by the path. - * If required the content of the bundle entry is extracted into a file - * on the file system. - * @param path The path to the entry to locate a File for. - * @return A File object to access the contents of the bundle entry. - */ - abstract public File getFile(String path); - - /** - * Locates a file name in this bundle and returns a BundleEntry object - * - * @param path path of the entry to locate in the bundle - * @return BundleEntry object or null if the file name - * does not exist in the bundle - */ - abstract public BundleEntry getEntry(String path); - - /** - * Allows to access the entries of the bundle. - * Since the bundle content is usually a jar, this - * allows to access the jar contents. - * - * GetEntryPaths allows to enumerate the content of "path". - * If path is a directory, it is equivalent to listing the directory - * contents. The returned names are either files or directories - * themselves. If a returned name is a directory, it finishes with a - * slash. If a returned name is a file, it does not finish with a slash. - * @param path path of the entry to locate in the bundle - * @return an Enumeration of Strings that indicate the paths found or - * null if the path does not exist. - */ - abstract public Enumeration getEntryPaths(String path); - - /** - * Closes the BundleFile. - * @throws IOException if any error occurs. - */ - abstract public void close() throws IOException; - - /** - * Opens the BundleFiles. - * @throws IOException if any error occurs. - */ - abstract public void open() throws IOException; - - /** - * Determines if any BundleEntries exist in the given directory path. - * @param dir The directory path to check existence of. - * @return true if the BundleFile contains entries under the given directory path; - * false otherwise. - */ - abstract public boolean containsDir(String dir); - - /** - * Returns a URL to access the contents of the entry specified by the path - * @param path the path to the resource - * @param hostBundleID the host bundle ID - */ - public URL getResourceURL(String path, long hostBundleID) { - return getResourceURL(path, hostBundleID, 0); - } - - /** - * Returns a URL to access the contents of the entry specified by the path - * @param path the path to the resource - * @param hostBundleID the host bundle ID - * @param index the resource index - */ - public URL getResourceURL(String path, long hostBundleID, int index) { - BundleEntry bundleEntry = getEntry(path); - if (bundleEntry == null) - return null; - if (path.length() == 0 || path.charAt(0) != '/') - path = '/' + path; - try { - //use the constant string for the protocol to prevent duplication - return secureAction.getURL(Constants.OSGI_RESOURCE_URL_PROTOCOL, Long.toString(hostBundleID), index, path, new Handler(bundleEntry)); - } catch (MalformedURLException e) { - return null; - } - } - - /** - * A BundleFile that uses a ZipFile as it base file. - */ - public static class ZipBundleFile extends BundleFile { - /** - * The bundle data - */ - protected BundleData bundledata; - /** - * The zip file - */ - protected ZipFile zipFile; - /** - * The closed flag - */ - protected boolean closed = true; - - /** - * Constructs a ZipBundle File - * @param basefile the base file - * @param bundledata the bundle data - * @throws IOException - */ - public ZipBundleFile(File basefile, BundleData bundledata) throws IOException { - super(basefile); - if (!secureAction.exists(basefile)) - throw new IOException(NLS.bind(AdaptorMsg.ADAPTER_FILEEXIST_EXCEPTION, basefile)); - this.bundledata = bundledata; - this.closed = true; - } - - /** - * Checks if the zip file is open - * @return true if the zip file is open - */ - protected boolean checkedOpen() { - try { - return getZipFile() != null; - } catch (IOException e) { - AbstractBundleData abstractData = (AbstractBundleData) bundledata; - abstractData.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, abstractData.getBundle(), e); - return false; - } - } - - /** - * Opens the ZipFile for this bundle file - * @return an open ZipFile for this bundle file - * @throws IOException - */ - protected ZipFile basicOpen() throws IOException { - return secureAction.getZipFile(this.basefile); - } - - /** - * Returns an open ZipFile for this bundle file. If an open - * ZipFile does not exist then a new one is created and - * returned. - * @return an open ZipFile for this bundle - * @throws IOException - */ - protected ZipFile getZipFile() throws IOException { - if (closed) { - zipFile = basicOpen(); - closed = false; - } - return zipFile; - } - - private ZipEntry getZipEntry(String path) { - if (path.length() > 0 && path.charAt(0) == '/') - path = path.substring(1); - ZipEntry entry = zipFile.getEntry(path); - if (entry != null && entry.getSize() == 0 && !entry.isDirectory()) { - // work around the directory bug see bug 83542 - ZipEntry dirEntry = zipFile.getEntry(path + '/'); - if (dirEntry != null) - entry = dirEntry; - } - return entry; - } - - /** - * Extracts a directory and all sub content to disk - * @param dirName the directory name to extract - * @return the File used to extract the content to. A value - * of <code>null</code> is returned if the directory to extract does - * not exist or if content extraction is not supported. - */ - protected File extractDirectory(String dirName) { - if (!checkedOpen()) - return null; - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - String entryPath = ((ZipEntry) entries.nextElement()).getName(); - if (entryPath.startsWith(dirName) && !entryPath.endsWith("/")) //$NON-NLS-1$ - getFile(entryPath); - } - return getExtractFile(dirName); - } - - private File getExtractFile(String entryName) { - if (!(bundledata instanceof AbstractBundleData)) - return null; - String path = ".cp"; /* put all these entries in this subdir *///$NON-NLS-1$ - String name = entryName.replace('/', File.separatorChar); - if ((name.length() > 1) && (name.charAt(0) == File.separatorChar)) /* if name has a leading slash */ - path = path.concat(name); - else - path = path + File.separator + name; - // first check the child generation dir - File childGenDir = ((AbstractBundleData) bundledata).getGenerationDir(); - if (childGenDir != null) { - File childPath = new File(childGenDir, path); - if (childPath.exists()) - return childPath; - } - // now check the parent - File parentGenDir = ((AbstractBundleData) bundledata).getParentGenerationDir(); - if (parentGenDir != null) { - // there is a parent generation check if the file exists - File parentPath = new File(parentGenDir, path); - if (parentPath.exists()) - // only use the parent generation file if it exists; do not extract there - return parentPath; - } - // did not exist in both locations; create a file for extraction. - File bundleGenerationDir = ((AbstractBundleData) bundledata).createGenerationDir(); - /* if the generation dir exists, then we have place to cache */ - if (bundleGenerationDir != null && bundleGenerationDir.exists()) - return new File(bundleGenerationDir, path); - return null; - } - - public File getFile(String entry) { - if (!checkedOpen()) - return null; - ZipEntry zipEntry = getZipEntry(entry); - if (zipEntry == null) { - return null; - } - - try { - File nested = getExtractFile(zipEntry.getName()); - if (nested != null) { - if (nested.exists()) { - /* the entry is already cached */ - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("File already present: " + nested.getPath()); //$NON-NLS-1$ - } - } else { - if (zipEntry.getName().endsWith("/")) { //$NON-NLS-1$ - if (!nested.mkdirs()) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to create directory: " + nested.getPath()); //$NON-NLS-1$ - } - throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, nested.getAbsolutePath())); - } - extractDirectory(zipEntry.getName()); - } else { - InputStream in = zipFile.getInputStream(zipEntry); - if (in == null) - return null; - /* the entry has not been cached */ - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Creating file: " + nested.getPath()); //$NON-NLS-1$ - } - /* create the necessary directories */ - File dir = new File(nested.getParent()); - if (!dir.exists() && !dir.mkdirs()) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to create directory: " + dir.getPath()); //$NON-NLS-1$ - } - throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, dir.getAbsolutePath())); - } - /* copy the entry to the cache */ - AbstractFrameworkAdaptor.readFile(in, nested); - } - } - - return nested; - } - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.printStackTrace(e); - } - } - return null; - } - - public boolean containsDir(String dir) { - if (!checkedOpen()) - return false; - if (dir == null) - return false; - - if (dir.length() == 0) - return true; - - if (dir.charAt(0) == '/') { - if (dir.length() == 1) - return true; - dir = dir.substring(1); - } - - if (dir.length() > 0 && dir.charAt(dir.length() - 1) != '/') - dir = dir + '/'; - - Enumeration entries = zipFile.entries(); - ZipEntry zipEntry; - String entryPath; - while (entries.hasMoreElements()) { - zipEntry = (ZipEntry) entries.nextElement(); - entryPath = zipEntry.getName(); - if (entryPath.startsWith(dir)) { - return true; - } - } - return false; - } - - public BundleEntry getEntry(String path) { - if (!checkedOpen()) - return null; - ZipEntry zipEntry = getZipEntry(path); - if (zipEntry == null) { - if (path.length() == 0 || path.charAt(path.length() - 1) == '/') { - // this is a directory request lets see if any entries exist in this directory - if (containsDir(path)) - return new BundleEntry.DirZipBundleEntry(this, path); - } - return null; - } - - return new BundleEntry.ZipBundleEntry(zipEntry, this); - - } - - public Enumeration getEntryPaths(String path) { - if (!checkedOpen()) - return null; - if (path == null) { - throw new NullPointerException(); - } - - if (path.length() > 0 && path.charAt(0) == '/') { - path = path.substring(1); - } - if (path.length() > 0 && path.charAt(path.length() - 1) != '/') { - path = new StringBuffer(path).append("/").toString(); //$NON-NLS-1$ - } - - Vector vEntries = new Vector(); - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry zipEntry = (ZipEntry) entries.nextElement(); - String entryPath = zipEntry.getName(); - if (entryPath.startsWith(path)) { - if (path.length() < entryPath.length()) { - if (entryPath.lastIndexOf('/') < path.length()) { - vEntries.add(entryPath); - } else { - entryPath = entryPath.substring(path.length()); - int slash = entryPath.indexOf('/'); - entryPath = path + entryPath.substring(0, slash + 1); - if (!vEntries.contains(entryPath)) { - vEntries.add(entryPath); - } - } - } - } - } - return vEntries.size() == 0 ? null : vEntries.elements(); - } - - public void close() throws IOException { - if (!closed) { - closed = true; - zipFile.close(); - } - } - - public void open() { - //do nothing - } - - } - - /** - * A BundleFile that uses a directory as its base file. - */ - public static class DirBundleFile extends BundleFile { - - /** - * Constructs a DirBundleFile - * @param basefile the base file - * @throws IOException - */ - public DirBundleFile(File basefile) throws IOException { - super(basefile); - if (!secureAction.exists(basefile) || !secureAction.isDirectory(basefile)) { - throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_EXCEPTION, basefile)); - } - } - - public File getFile(String path) { - File filePath = new File(this.basefile, path); - if (secureAction.exists(filePath)) { - return filePath; - } - return null; - } - - public BundleEntry getEntry(String path) { - File filePath = new File(this.basefile, path); - if (!secureAction.exists(filePath)) { - return null; - } - return new BundleEntry.FileBundleEntry(filePath, path); - } - - public boolean containsDir(String dir) { - File dirPath = new File(this.basefile, dir); - return secureAction.exists(dirPath) && secureAction.isDirectory(dirPath); - } - - public Enumeration getEntryPaths(final String path) { - final java.io.File pathFile = new java.io.File(basefile, path); - if (!secureAction.exists(pathFile)) - return null; - if (secureAction.isDirectory(pathFile)) { - final String[] fileList = secureAction.list(pathFile); - if (fileList == null || fileList.length == 0) - return null; - final String dirPath = path.length() == 0 || path.charAt(path.length() - 1) == '/' ? path : path + '/'; - return new Enumeration() { - int cur = 0; - - public boolean hasMoreElements() { - return fileList != null && cur < fileList.length; - } - - public Object nextElement() { - if (!hasMoreElements()) { - throw new NoSuchElementException(); - } - java.io.File childFile = new java.io.File(pathFile, fileList[cur]); - StringBuffer sb = new StringBuffer(dirPath).append(fileList[cur++]); - if (secureAction.isDirectory(childFile)) { - sb.append("/"); //$NON-NLS-1$ - } - return sb.toString(); - } - - }; - } - return new Enumeration() { - int cur = 0; - - public boolean hasMoreElements() { - return cur < 1; - } - - public Object nextElement() { - if (cur == 0) { - cur = 1; - return path; - } - throw new NoSuchElementException(); - } - }; - } - - public void close() { - // nothing to do. - } - - public void open() { - // nothing to do. - } - } - - /** - * A NestedDirBundleFile uses another BundleFile as its source but - * accesses all of its resources relative to a nested directory within - * the other BundleFile object. This is used to support zipped bundles - * that use a Bundle-ClassPath with an nested directory specified. - * <p> - * For Example: - * <pre> - * Bundle-ClassPath: nested.jar,nesteddir/ - * </pre> - */ - public static class NestedDirBundleFile extends BundleFile { - BundleFile baseBundleFile; - String cp; - - /** - * Constructs a NestedDirBundleFile - * @param baseBundlefile the base bundle file - * @param cp - */ - public NestedDirBundleFile(BundleFile baseBundlefile, String cp) { - super(baseBundlefile.basefile); - this.baseBundleFile = baseBundlefile; - this.cp = cp; - if (cp.charAt(cp.length() - 1) != '/') { - this.cp = this.cp + '/'; - } - } - - public void close() { - // do nothing. - } - - public BundleEntry getEntry(String path) { - if (path.length() > 0 && path.charAt(0) == '/') - path = path.substring(1); - String newpath = new StringBuffer(cp).append(path).toString(); - return baseBundleFile.getEntry(newpath); - } - - public boolean containsDir(String dir) { - if (dir == null) - return false; - - if (dir.length() > 0 && dir.charAt(0) == '/') - dir = dir.substring(1); - String newdir = new StringBuffer(cp).append(dir).toString(); - return baseBundleFile.containsDir(newdir); - } - - public Enumeration getEntryPaths(String path) { - // getEntryPaths is only valid if this is a root bundle file. - return null; - } - - public File getFile(String entry) { - // getFile is only valid if this is a root bundle file. - return null; - } - - public void open() throws IOException{ - // do nothing - } - } - - /** - * Returns the base file for this BundleFile - * @return the base file for this BundleFile - */ - public File getBaseFile() { - return basefile; - } -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/BundleInstaller.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/BundleInstaller.java deleted file mode 100644 index 66235db51..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/BundleInstaller.java +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004 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.adaptor.core; - -import org.eclipse.osgi.service.resolver.BundleDescription; -import org.osgi.framework.BundleException; - -/** - * A bundle installer allows the platform admin implementation to - * delegate the behavior of installing/uninstalling bundles to - * another object. - * <p> - * Clients may implement this interface. - * </p> - * @since 3.1 - * @see StateManager#commit - */ -public interface BundleInstaller { - /** - * Installs a bundle associated with the specified BundleDescription - * @param toInstall the BundleDescription associated with the bundle to install - * @throws BundleException if an error occurs while installing the bundle - */ - public void installBundle(BundleDescription toInstall) throws BundleException; - - /** - * Uninstalls a bundle associated with the specified BundleDescription - * @param toUninstall the BundleDescriptoin associated with the bundle to uninstall - * @throws BundleException if an error occurs while uninstalling the bundle - */ - public void uninstallBundle(BundleDescription toUninstall) throws BundleException; - - /** - * Updates a bundle associated with the specified BundleDescription - * @param toRefresh the BundleDescription associated with the bundle to update - * @throws BundleException if an error occurs while updating the bundle - */ - public void updateBundle(BundleDescription toRefresh) throws BundleException; -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/DefaultClassLoader.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/DefaultClassLoader.java deleted file mode 100644 index fe83979a7..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/DefaultClassLoader.java +++ /dev/null @@ -1,722 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004, 2005 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.adaptor.core; - -import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.*; -import java.security.cert.Certificate; -import java.util.*; -import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; -import org.eclipse.osgi.framework.debug.Debug; -import org.eclipse.osgi.util.NLS; -import org.osgi.framework.BundleException; -import org.osgi.framework.FrameworkEvent; - -/** - * A concrete implementation of BundleClassLoader. This implementation - * consolidates all Bundle-ClassPath entries into a single ClassLoader. - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -public class DefaultClassLoader extends AbstractClassLoader { - /** - * A PermissionCollection for AllPermissions; shared across all ProtectionDomains when security is disabled - */ - static final PermissionCollection ALLPERMISSIONS; - static { - AllPermission allPerm = new AllPermission(); - ALLPERMISSIONS = allPerm.newPermissionCollection(); - if (ALLPERMISSIONS != null) - ALLPERMISSIONS.add(allPerm); - } - /** - * The BundleData object for this BundleClassLoader - */ - protected AbstractBundleData hostdata; - - /** - * The ClasspathEntries for this BundleClassLoader. Each ClasspathEntry object - * represents on Bundle-ClassPath entry. - */ - protected ClasspathEntry[] classpathEntries; - - /** - * A list of fragment classpaths for this classloader - */ - protected Vector fragClasspaths; //TODO This should be an array or an arraylist if the synchronization is not required - - /** - * The buffer size to use when loading classes. This value is used - * only if we cannot determine the size of the class we are loading. - */ - protected int buffersize = 8 * 1024; //TODO Could not that be a constant? - - /** - * BundleClassLoader constructor. - * @param delegate The ClassLoaderDelegate for this ClassLoader. - * @param domain The ProtectionDomain for this ClassLoader. - * @param classpath An array of Bundle-ClassPath entries to - * use for loading classes and resources. This is specified by the - * Bundle-ClassPath manifest entry. - * @param parent The parent ClassLoader. - * @param bundledata The BundleData for this ClassLoader - */ - public DefaultClassLoader(ClassLoaderDelegate delegate, ProtectionDomain domain, String[] classpath, ClassLoader parent, AbstractBundleData bundledata) { - super(delegate, domain, classpath, parent); - this.hostdata = bundledata; - - try { - hostdata.open(); /* make sure the BundleData is open */ - } catch (IOException e) { - hostdata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, hostdata.getBundle(), e); - } - } - - /** - * @see org.eclipse.osgi.framework.adaptor.BundleClassLoader#initialize() - */ - public void initialize() { - classpathEntries = buildClasspath(hostclasspath, hostdata, hostdomain); - } - - /** - * @see org.eclipse.osgi.framework.adaptor.BundleClassLoader#attachFragment(BundleData, ProtectionDomain, String[]) - */ - public void attachFragment(org.eclipse.osgi.framework.adaptor.BundleData bundledata, ProtectionDomain domain, String[] classpath) { - AbstractBundleData abstractbundledata = (AbstractBundleData) bundledata; - try { - bundledata.open(); /* make sure the BundleData is open */ - } catch (IOException e) { - - abstractbundledata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, abstractbundledata.getBundle(), e); - } - ClasspathEntry[] fragEntries = buildClasspath(classpath, abstractbundledata, domain); - FragmentClasspath fragClasspath = new FragmentClasspath(fragEntries, abstractbundledata, domain); - insertFragment(fragClasspath); - } - - /** - * Inserts a fragment classpath to into the list of fragments for this host. - * Fragments are inserted into the list according to the fragment's - * Bundle ID. - * @param fragClasspath The FragmentClasspath to insert. - */ - protected synchronized void insertFragment(FragmentClasspath fragClasspath) { - if (fragClasspaths == null) { - // First fragment to attach. Simply create the list and add the fragment. - fragClasspaths = new Vector(10); - fragClasspaths.addElement(fragClasspath); - return; - } - - // Find a place in the fragment list to insert this fragment. - int size = fragClasspaths.size(); - long fragID = fragClasspath.bundledata.getBundleID(); - for (int i = 0; i < size; i++) { - long otherID = ((FragmentClasspath) fragClasspaths.elementAt(i)).bundledata.getBundleID(); - if (fragID < otherID) { - fragClasspaths.insertElementAt(fragClasspath, i); - return; - } - } - // This fragment has the highest ID; put it at the end of the list. - fragClasspaths.addElement(fragClasspath); - } - - /** - * Returns a string of the symbolic name and version - * @return a string of the symbolic name and version - */ - protected String getBundleSymbolicName() { - return hostdata.getSymbolicName() + "_" + hostdata.getVersion(); //$NON-NLS-1$ - } - - /** - * Returns the host BundleData for this classloader - * @return the host BundleData for this classloader - */ - public AbstractBundleData getHostData() { - return hostdata; - } - - /** - * Returns a list of FragmentClasspath objects for the currently attached fragments - * @return a list of FragmentClasspath objects for the currently attached fragments - */ - public FragmentClasspath[] getFragClasspaths() { - if (fragClasspaths == null) - return null; - return (FragmentClasspath[]) fragClasspaths.toArray(new FragmentClasspath[fragClasspaths.size()]); - } - - /** - * Gets a ClasspathEntry object for the specified ClassPath entry. - * @param cp The ClassPath entry to get the ClasspathEntry for. - * @param bundledata The BundleData that the ClassPath entry is for. - * @param domain The ProtectionDomain for the ClassPath entry. - * @return The ClasspathEntry object for the ClassPath entry. - */ - protected ClasspathEntry getClasspath(String cp, AbstractBundleData bundledata, ProtectionDomain domain) { - BundleFile bundlefile = null; - File file; - // check for internal library jars - if ((file = bundledata.getBaseBundleFile().getFile(cp)) != null) - bundlefile = createBundleFile(file, bundledata); - // check for intenral library directories in a bundle jar file - if (bundlefile == null && bundledata.getBaseBundleFile().containsDir(cp)) - bundlefile = new BundleFile.NestedDirBundleFile(bundledata.getBaseBundleFile(), cp); - // if in dev mode, try using the cp as an absolute path - if (bundlefile == null && DevClassPathHelper.inDevelopmentMode()) - return getExternalClassPath(cp, bundledata, domain); - if (bundlefile != null) - return createClassPathEntry(bundlefile, domain); - return null; - } - - /** - * Gets a ClasspathEntry object for the specified classpath entry which is external to the - * bundledata. - * @param cp The ClassPath entry to get the ClasspathEntry for. - * @param bundledata The BundleData that the ClassPath entry is for. - * @param domain The ProtectionDomain for the ClassPath entry. - * @return The ClasspathEntry object for the ClassPath entry. - */ - protected ClasspathEntry getExternalClassPath(String cp, AbstractBundleData bundledata, ProtectionDomain domain) { - File file = new File(cp); - if (!file.isAbsolute()) - return null; - BundleFile bundlefile = createBundleFile(file, bundledata); - if (bundlefile != null) - return createClassPathEntry(bundlefile, domain); - return null; - } - - /** - * Creates a BundleFile object for a classpath entry - * @param file the file object used to create a BundleFile - * @param bundledata the bundle data - * @return a BundleFile object for a classpath entry - */ - protected BundleFile createBundleFile(File file, AbstractBundleData bundledata) { - if (file == null || !file.exists()) - return null; - try { - return hostdata.getAdaptor().createBundleFile(file, bundledata); - } catch (IOException e) { - bundledata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundledata.getBundle(), e); - } - return null; - } - - /** - * @see ClassLoader#findClass(java.lang.String) - */ - protected synchronized Class findClass(String name) throws ClassNotFoundException { - // must call findLoadedClass here even if it was called earlier, - // the findLoadedClass and defineClass calls must be atomic - Class result = findLoadedClass(name); - if (result != null) - return result; - for (int i = 0; i < classpathEntries.length; i++) { - if (classpathEntries[i] != null) { - result = findClassImpl(name, classpathEntries[i]); - if (result != null) - return result; - } - } - // look in fragments. - if (fragClasspaths != null) { - int size = fragClasspaths.size(); - for (int i = 0; i < size; i++) { - FragmentClasspath fragCP = (FragmentClasspath) fragClasspaths.elementAt(i); - for (int j = 0; j < fragCP.classpathEntries.length; j++) { - result = findClassImpl(name, fragCP.classpathEntries[j]); - if (result != null) - return result; - } - } - } - throw new ClassNotFoundException(name); - } - - /** - * Finds a class in the BundleFile. If a class is found then the class - * is defined using the ProtectionDomain bundledomain. - * @param name The name of the class to find. - * @param classpathEntry The ClasspathEntry to find the class in. - * @return The loaded class object or null if the class is not found. - */ - protected Class findClassImpl(String name, ClasspathEntry classpathEntry) { - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println("BundleClassLoader[" + hostdata + "].findClass(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ - } - - String filename = name.replace('.', '/').concat(".class"); //$NON-NLS-1$ - - BundleEntry entry = classpathEntry.getBundleFile().getEntry(filename); - - if (entry == null) { - return null; - } - - InputStream in; - try { - in = entry.getInputStream(); - } catch (IOException e) { - return null; - } - - int length = (int) entry.getSize(); - byte[] classbytes; - int bytesread = 0; - int readcount; - - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println(" about to read " + length + " bytes from " + filename); //$NON-NLS-1$ //$NON-NLS-2$ - } - - try { - try { - if (length > 0) { - classbytes = new byte[length]; - - readloop: for (; bytesread < length; bytesread += readcount) { - readcount = in.read(classbytes, bytesread, length - bytesread); - - if (readcount <= 0) /* if we didn't read anything */{ - break readloop; /* leave the loop */ - } - } - } else /* BundleEntry does not know its own length! */{ - length = buffersize; - classbytes = new byte[length]; - - readloop: while (true) { - for (; bytesread < length; bytesread += readcount) { - readcount = in.read(classbytes, bytesread, length - bytesread); - - if (readcount <= 0) /* if we didn't read anything */{ - break readloop; /* leave the loop */ - } - } - - byte[] oldbytes = classbytes; - length += buffersize; - classbytes = new byte[length]; - System.arraycopy(oldbytes, 0, classbytes, 0, bytesread); - } - } - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println(" IOException reading " + filename + " from " + hostdata); //$NON-NLS-1$ //$NON-NLS-2$ - } - - return null; - } - } finally { - try { - in.close(); - } catch (IOException ee) { - // nothing to do here - } - } - - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println(" read " + bytesread + " bytes from " + filename); //$NON-NLS-1$ //$NON-NLS-2$ - Debug.println(" defining class " + name); //$NON-NLS-1$ - } - - try { - return (defineClass(name, classbytes, 0, bytesread, classpathEntry)); - } catch (Error e) { - if (Debug.DEBUG && Debug.DEBUG_LOADER) { - Debug.println(" error defining class " + name); //$NON-NLS-1$ - } - - throw e; - } - } - - /** - * Defines a class for this classloader - * @param name the name of the class - * @param classbytes the class bytes - * @param off the offset in the class bytes array - * @param len the legth of the class bytes - * @param classpathEntry the classpath entry used for the class - * @return a loaded Class object - * @throws ClassFormatError if the class has a format error - */ - protected Class defineClass(String name, byte[] classbytes, int off, int len, ClasspathEntry classpathEntry) throws ClassFormatError { - if (name != null && name.startsWith("java.")) { //$NON-NLS-1$ - // To work around the security issue that prevents any - // other classloader except for the bootstrap classloader - // from loading packages that start with java. - name = null; - } - return defineClass(name, classbytes, off, len, classpathEntry.getProtectionDomain()); - } - - /** - * @see ClassLoader#findResource(java.lang.String) - */ - protected URL findResource(String name) { - URL result = null; - for (int i = 0; i < classpathEntries.length; i++) { - if (classpathEntries[i] != null) { - result = findResourceImpl(name, classpathEntries[i].getBundleFile()); - if (result != null) - return result; - } - } - // look in fragments - if (fragClasspaths != null) { - int size = fragClasspaths.size(); - for (int i = 0; i < size; i++) { - FragmentClasspath fragCP = (FragmentClasspath) fragClasspaths.elementAt(i); - for (int j = 0; j < fragCP.classpathEntries.length; j++) { - result = findResourceImpl(name, fragCP.classpathEntries[j].getBundleFile()); - if (result != null) - return result; - } - } - } - return null; - } - - /** - * Looks in the specified BundleFile for the resource. - * @param name The name of the resource to find. - * @param bundlefile The BundleFile to look in. - * @return A URL to the resource or null if the resource does not exist. - */ - protected URL findResourceImpl(String name, BundleFile bundlefile) { - return findResourceImpl(name, bundlefile, 0); - } - - /** - * Looks in the specified BundleFile for the resource. - * @param name The name of the resource to find. - * @param bundlefile The BundleFile to look in. - * @param index the index of the resource. - * @return A URL to the resource or null if the resource does not exist. - */ - protected URL findResourceImpl(String name, BundleFile bundlefile, int index) { - return bundlefile.getResourceURL(name, hostdata.getBundleID(), index); - } - - /** - * @see org.eclipse.osgi.framework.adaptor.BundleClassLoader#findLocalResources(String) - */ - public Enumeration findLocalResources(String resource) { - Vector resources = new Vector(6); // use a Vector instead of ArrayList because we need an enumeration - for (int i = 0; i < classpathEntries.length; i++) { - if (classpathEntries[i] != null) { - URL url = findResourceImpl(resource, classpathEntries[i].getBundleFile(), resources.size()); - if (url != null) - resources.addElement(url); - } - } - // look in fragments - if (fragClasspaths != null) { - int size = fragClasspaths.size(); - for (int i = 0; i < size; i++) { - FragmentClasspath fragCP = (FragmentClasspath) fragClasspaths.elementAt(i); - for (int j = 0; j < fragCP.classpathEntries.length; j++) { - URL url = findResourceImpl(resource, fragCP.classpathEntries[j].getBundleFile(), resources.size()); - if (url != null) - resources.addElement(url); - } - } - } - if (resources.size() > 0) - return resources.elements(); - return null; - } - - /** - * @see AbstractClassLoader#findLocalObject(String) - */ - public Object findLocalObject(String object) { - BundleEntry result = null; - for (int i = 0; i < classpathEntries.length; i++) { - if (classpathEntries[i] != null) { - result = findObjectImpl(object, classpathEntries[i].getBundleFile()); - if (result != null) { - return result; - } - } - } - // look in fragments - if (fragClasspaths != null) { - int size = fragClasspaths.size(); - for (int i = 0; i < size; i++) { - FragmentClasspath fragCP = (FragmentClasspath) fragClasspaths.elementAt(i); - for (int j = 0; j < fragCP.classpathEntries.length; j++) { - result = findObjectImpl(object, fragCP.classpathEntries[j].getBundleFile()); - if (result != null) { - return result; - } - } - } - } - return null; - } - - /** - * @see AbstractClassLoader#findLocalObjects(String) - */ - public Enumeration findLocalObjects(String object) { - Vector objects = new Vector(6); // use a Vector instead of ArrayList because we need an enumeration - for (int i = 0; i < classpathEntries.length; i++) { - if (classpathEntries[i] != null) { - Object result = findObjectImpl(object, classpathEntries[i].getBundleFile()); - if (result != null) - objects.addElement(result); - } - } - // look in fragments - if (fragClasspaths != null) { - int size = fragClasspaths.size(); - for (int i = 0; i < size; i++) { - FragmentClasspath fragCP = (FragmentClasspath) fragClasspaths.elementAt(i); - for (int j = 0; j < fragCP.classpathEntries.length; j++) { - Object result = findObjectImpl(object, fragCP.classpathEntries[j].getBundleFile()); - if (result != null) - objects.addElement(result); - } - } - } - if (objects.size() > 0) - return objects.elements(); - return null; - } - - /** - * Looks in the specified BundleFile for the entry. - * @param object The name of the entry to find. - * @param bundleFile The BundleFile to look in. - * @return a bundle entry for the specified entry or <code>null</code> if the - * entry does not exist - */ - protected BundleEntry findObjectImpl(String object, BundleFile bundleFile) { - return bundleFile.getEntry(object); - } - - /** - * @see org.eclipse.osgi.framework.adaptor.BundleClassLoader#close() - */ - public void close() { - super.close(); - if (classpathEntries != null) { - for (int i = 0; i < classpathEntries.length; i++) { - if (classpathEntries[i] != null) { - try { - classpathEntries[i].getBundleFile().close(); - } catch (IOException e) { - hostdata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, hostdata.getBundle(), e); - } - } - } - } - if (fragClasspaths != null) { - int size = fragClasspaths.size(); - for (int i = 0; i < size; i++) { - FragmentClasspath fragCP = (FragmentClasspath) fragClasspaths.elementAt(i); - fragCP.close(); - } - } - } - - /** - * Builds the classpath entry objects for this classloader - * @param classpath a list of classpath entries to build - * @param bundledata the bundle data - * @param domain the ProtectionDomain for the classpath entry objects - * @return - */ - protected ClasspathEntry[] buildClasspath(String[] classpath, AbstractBundleData bundledata, ProtectionDomain domain) { - ArrayList result = new ArrayList(classpath.length); - // if in dev mode add the dev entries - addDefaultDevEntries(result, bundledata, domain); - // add the regular classpath entries. - for (int i = 0; i < classpath.length; i++) - findClassPathEntry(result, classpath[i], bundledata, domain); - return (ClasspathEntry[]) result.toArray(new ClasspathEntry[result.size()]); - } - - /** - * Adds the default development classpath entries - * @param result a list of current classpath entries. This list is modified by this method to add - * a new classpath entry. - * @param bundledata the bundle data - * @param domain the ProtectionDomain for the classpath entry - */ - protected void addDefaultDevEntries(ArrayList result, AbstractBundleData bundledata, ProtectionDomain domain) { - String[] devClassPath = !DevClassPathHelper.inDevelopmentMode() ? null : DevClassPathHelper.getDevClassPath(bundledata.getSymbolicName()); - if (devClassPath == null) - return; // not in dev mode return - for (int i = 0; i < devClassPath.length; i++) - findClassPathEntry(result, devClassPath[i], bundledata, domain); - } - - /** - * Finds a classpath entry for this classloader - * @param result a list of current classpath entries. This list is modified by this method to add - * a new classpath entry. - * @param entry the path to the entry to find - * @param bundledata the bundle data - * @param domain the ProtectionDomain for the classpath entry - */ - protected void findClassPathEntry(ArrayList result, String entry, AbstractBundleData bundledata, ProtectionDomain domain) { - if (!addClassPathEntry(result, entry, bundledata, domain)) { - String[] devCP = !DevClassPathHelper.inDevelopmentMode() ? null : DevClassPathHelper.getDevClassPath(bundledata.getSymbolicName()); - if (devCP == null || devCP.length == 0) { - BundleException be = new BundleException(NLS.bind(AdaptorMsg.BUNDLE_CLASSPATH_ENTRY_NOT_FOUND_EXCEPTION, entry, bundledata.getLocation())); - bundledata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.INFO, bundledata.getBundle(), be); - } - } - } - - /** - * Adds a classpath entry to this classloader - * @param result a list of current classpath entries. This list is modified by this method to add - * a new classpath entry. - * @param entry the path to the entry to add - * @param bundledata the bundle data - * @param domain the ProtectionDomain for the classpath entry - * @return true if a classpath entry was added to the result; false if the classpath entry could - * not be found - */ - protected boolean addClassPathEntry(ArrayList result, String entry, AbstractBundleData bundledata, ProtectionDomain domain) { - if (entry.equals(".")) { //$NON-NLS-1$ - result.add(createClassPathEntry(bundledata.getBaseBundleFile(), domain)); - return true; - } - Object element = getClasspath(entry, bundledata, domain); - if (element != null) { - result.add(element); - return true; - } - // need to check in fragments for the classpath entry. - // only check for fragments if the bundledata is the hostdata. - if (fragClasspaths != null && hostdata == bundledata) { - int size = fragClasspaths.size(); - for (int i = 0; i < size; i++) { - FragmentClasspath fragCP = (FragmentClasspath) fragClasspaths.elementAt(i); - element = getClasspath(entry, fragCP.bundledata, fragCP.domain); - if (element != null) { - result.add(element); - return true; - } - } - } - return false; - } - - /** - * Creates a ClasspathEntry from a BundleFile and ProtectionDomain. - * @param bundlefile the BundleFile. - * @param domain the ProtectionDomain - * @return the ClasspathEntry - */ - protected ClasspathEntry createClassPathEntry(BundleFile bundlefile, ProtectionDomain domain) { - return new ClasspathEntry(bundlefile, domain); - } - - /** - * A data structure to hold information about a fragment classpath. - */ - protected class FragmentClasspath { - /** The ClasspathEntries of the fragments Bundle-Classpath */ - protected ClasspathEntry[] classpathEntries; - /** The BundleData of the fragment */ - protected AbstractBundleData bundledata; - /** The ProtectionDomain of the fragment */ - protected ProtectionDomain domain; - - protected FragmentClasspath(ClasspathEntry[] classpathEntries, AbstractBundleData bundledata, ProtectionDomain domain) { - this.classpathEntries = classpathEntries; - this.bundledata = bundledata; - this.domain = domain; - } - - protected void close() { - for (int i = 0; i < classpathEntries.length; i++) { - try { - classpathEntries[i].getBundleFile().close(); - } catch (IOException e) { - bundledata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundledata.getBundle(), e); - } - } - } - - public AbstractBundleData getBundleData() { - return bundledata; - } - } - - /** - * A data structure to hold information about a classpath entry. - */ - protected class ClasspathEntry { - protected BundleFile bundlefile; - protected ProtectionDomain domain; - - protected ClasspathEntry(BundleFile bundlefile, ProtectionDomain domain) { - this.bundlefile = bundlefile; - this.domain = createProtectionDomain(domain); - } - - public BundleFile getBundleFile() { - return bundlefile; - } - - public ProtectionDomain getProtectionDomain() { - return domain; - } - - /* - * Creates a ProtectionDomain using the permissions of the specified baseDomain - */ - protected ProtectionDomain createProtectionDomain(ProtectionDomain baseDomain) { - // create a protection domain which knows about the codesource for this classpath entry (bug 89904) - try { - // use the permissions supplied by the domain passed in from the framework - PermissionCollection permissions; - if (baseDomain != null) - permissions = baseDomain.getPermissions(); - else - // no domain specified. Better use a collection that has all permissions - // this is done just incase someone sets the security manager later - permissions = ALLPERMISSIONS; - return new ClasspathDomain(bundlefile.getBaseFile().toURL(), permissions); - } catch (MalformedURLException e) { - // Failed to create our own domain; just return the baseDomain - return baseDomain; - } - } - } - - /* - * Very simple protection domain that uses a URL to create a CodeSource for a ProtectionDomain - */ - protected class ClasspathDomain extends ProtectionDomain { - public ClasspathDomain(URL codeLocation, PermissionCollection permissions) { - super(new CodeSource(codeLocation, (Certificate[]) null), permissions); - } - } -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/SignedBundle.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/SignedBundle.java deleted file mode 100644 index 2459fc6a1..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/SignedBundle.java +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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.adaptor.core; - -import java.io.IOException; - -/** - * The SignedBundle class is used to support bundle signing. Every SignedBundle wraps a - * BundleFile object. A SignedBundle uses the wrapped BundleFile to extract signitures - * and digents from and validates input streams for the wrapped BundleFile. - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -public abstract class SignedBundle extends BundleFile { - /** - * Sets the BundleFile for this singed bundle. It will extract - * signatures and digests from the bundle file and validate input streams - * before using them from the bundle file. - * - * @param bundleFile the BundleFile to extract elements from. - * @throws IOException - */ - public abstract void setBundleFile(BundleFile bundleFile) throws IOException; - - /** - * Matches the distinguished name chains of a bundle's signers against a - * pattern of a distinguished name chain. - * - * @param pattern the pattern of distinguished name (DN) chains to match - * against the dnChain. Wildcards "*" can be used in three cases: - * <ol> - * <li>As a DN. In this case, the DN will consist of just the "*". - * It will match zero or more DNs. For example, "cn=me,c=US;*;cn=you" - * will match "cn=me,c=US";cn=you" and - * "cn=me,c=US;cn=her,c=CA;cn=you". - * <li>As a DN prefix. In this case, the DN must start with "*,". - * The wild card will match zero or more RDNs at the start of a DN. - * For example, "*,cn=me,c=US;cn=you" will match "cn=me,c=US";cn=you" - * and "ou=my org unit,o=my org,cn=me,c=US;cn=you"</li> - * <li>As a value. In this case the value of a name value pair in an - * RDN will be a "*". The wildcard will match any value for the given - * name. For example, "cn=*,c=US;cn=you" will match - * "cn=me,c=US";cn=you" and "cn=her,c=US;cn=you", but it will not - * match "ou=my org unit,c=US;cn=you". If the wildcard does not occur - * by itself in the value, it will not be used as a wildcard. In - * other words, "cn=m*,c=US;cn=you" represents the common name of - * "m*" not any common name starting with "m".</li> - * </ol> - * @return true if a dnChain matches the pattern. A value of false is returned - * if bundle signing is not supported. - * @throws IllegalArgumentException - */ - public abstract boolean matchDNChain(String pattern); -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/SignedBundleSupport.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/SignedBundleSupport.java deleted file mode 100644 index 3c237a668..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/SignedBundleSupport.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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.adaptor.core; - -/** - * Provides the implementation of signed bundle support for the framework adaptor. - * <p> - * Clients may implement this interface. - * </p> - * @since 3.1 - */ -public interface SignedBundleSupport { - /** - * Create a new SignedBundle object - * @return a new SignedBundle object - */ - public SignedBundle createSignedBundle(); - - /** - * Matches the distinguished name chain against a pattern of a distinguished name chain. - * - * @param pattern the pattern of distinguished name (DN) chains to match - * against the dnChain. - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#matchDNChain(String, String[]) - * @return true if a dnChain matches the pattern. A value of false is returned - * if bundle signing is not supported. - * @throws IllegalArgumentException - */ - public boolean matchDNChain(String pattern, String dnChain[]); -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/BundleResourceHandler.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/BundleResourceHandler.java index d0cd3fdbd..a7d663091 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/BundleResourceHandler.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/BundleResourceHandler.java @@ -13,8 +13,9 @@ package org.eclipse.osgi.framework.internal.core; import java.io.IOException; import java.net.*; -import org.eclipse.osgi.framework.adaptor.BundleClassLoader; -import org.eclipse.osgi.framework.adaptor.core.*; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.loader.BaseClassLoader; +import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg; import org.eclipse.osgi.util.NLS; import org.osgi.framework.*; @@ -133,14 +134,14 @@ public abstract class BundleResourceHandler extends URLStreamHandler { String bidString = url.getHost(); if (bidString == null) { - throw new IOException(NLS.bind(AdaptorMsg.URL_NO_BUNDLE_ID, url.toExternalForm())); + throw new IOException(NLS.bind(AdaptorMsg.URL_NO_BUNDLE_ID, url.toExternalForm())); } AbstractBundle bundle = null; long bundleID; try { bundleID = Long.parseLong(bidString); } catch (NumberFormatException nfe) { - throw new MalformedURLException(NLS.bind(AdaptorMsg.URL_INVALID_BUNDLE_ID, bidString)); + throw new MalformedURLException(NLS.bind(AdaptorMsg.URL_INVALID_BUNDLE_ID, bidString)); } bundle = (AbstractBundle) context.getBundle(bundleID); // check to make sure that this URL was created using the @@ -152,7 +153,7 @@ public abstract class BundleResourceHandler extends URLStreamHandler { } if (bundle == null) { - throw new IOException(NLS.bind(AdaptorMsg.URL_NO_BUNDLE_FOUND, url.toExternalForm())); + throw new IOException(NLS.bind(AdaptorMsg.URL_NO_BUNDLE_FOUND, url.toExternalForm())); } return (new BundleURLConnection(url, findBundleEntry(url, bundle))); } @@ -266,10 +267,10 @@ public abstract class BundleResourceHandler extends URLStreamHandler { } } - protected static BundleClassLoader getBundleClassLoader(AbstractBundle bundle) { + protected static BaseClassLoader getBundleClassLoader(AbstractBundle bundle) { BundleLoader loader = bundle.getBundleLoader(); if (loader == null) return null; - return loader.createClassLoader(); + return (BaseClassLoader) loader.createClassLoader(); } } diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/BundleURLConnection.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/BundleURLConnection.java index 51dedab44..e5da6a257 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/BundleURLConnection.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/BundleURLConnection.java @@ -1,10 +1,10 @@ /******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. + * Copyright (c) 2004, 2005 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 *******************************************************************************/ @@ -15,8 +15,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; -import org.eclipse.osgi.framework.adaptor.core.AdaptorMsg; -import org.eclipse.osgi.framework.adaptor.core.BundleEntry; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.internal.baseadaptor.AdaptorMsg; import org.eclipse.osgi.util.NLS; /** @@ -53,7 +53,7 @@ public class BundleURLConnection extends URLConnection { in = bundleEntry.getInputStream(); connected = true; } else { - throw new IOException(NLS.bind(AdaptorMsg.RESOURCE_NOT_FOUND_EXCEPTION, url)); + throw new IOException(NLS.bind(AdaptorMsg.RESOURCE_NOT_FOUND_EXCEPTION, url)); } } } @@ -78,6 +78,7 @@ public class BundleURLConnection extends URLConnection { if (in.markSupported()) contentType = guessContentTypeFromStream(in); } catch (IOException e) { + // do nothing } } } diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/DefaultPermissionStorage.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/DefaultPermissionStorage.java deleted file mode 100644 index d9409fd0d..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/DefaultPermissionStorage.java +++ /dev/null @@ -1,349 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2005 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.*; -import java.util.*; -import org.eclipse.osgi.framework.adaptor.PermissionStorage; -import org.eclipse.osgi.framework.adaptor.core.AbstractFrameworkAdaptor; -import org.eclipse.osgi.framework.adaptor.core.AdaptorMsg; -import org.eclipse.osgi.framework.debug.Debug; -import org.eclipse.osgi.framework.internal.reliablefile.*; -import org.eclipse.osgi.util.NLS; - -/** - * Class to model permission data storage. - */ - -public class DefaultPermissionStorage implements PermissionStorage { - /** Filename used to store the ConditionalPermissions. This name - * is relative to permissionDir.*/ - private static final String CONDPERMS = "condPerms"; //$NON-NLS-1$ - /** Directory into which permission data files are stored. */ - protected File permissionDir; - - /** List of permission files: String location => File permission file */ - protected Hashtable permissionFiles; - - /** Default permission data. */ - protected File defaultData; - - /** First permission data format version */ - protected static final int PERMISSIONDATA_VERSION_1 = 1; - - /** Current permission data format version */ - protected static final int PERMISSIONDATA_VERSION = PERMISSIONDATA_VERSION_1; - - /** - * Constructor. - * - * @throws IOException If an error occurs initializing the object. - */ - public DefaultPermissionStorage(AbstractFrameworkAdaptor adaptor) throws IOException { - permissionDir = new File(adaptor.getBundleStoreRootDir(), "permdata"); //$NON-NLS-1$ - permissionFiles = new Hashtable(); - - if (!permissionDir.exists() && !permissionDir.mkdirs()) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to create directory: " + permissionDir.getPath()); //$NON-NLS-1$ - } - - throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, permissionDir)); - } - - defaultData = new File(permissionDir, ".default"); //$NON-NLS-1$ - - loadLocations(); - } - - /** - * Returns the locations that have permission data assigned to them, - * that is, locations for which permission data - * exists in persistent storage. - * - * @return The locations that have permission data in - * persistent storage, or <tt>null</tt> if there is no permission data - * in persistent storage. - * @throws IOException If a failure occurs accessing peristent storage. - */ - public synchronized String[] getLocations() throws IOException { - int size = permissionFiles.size(); - - if (size == 0) { - return null; - } - - String[] locations = new String[size]; - - Enumeration keysEnum = permissionFiles.keys(); - - for (int i = 0; i < size; i++) { - locations[i] = (String) keysEnum.nextElement(); - } - - return locations; - } - - /** - * Gets the permission data assigned to the specified - * location. - * - * @param location The location whose permission data is to - * be returned. - * - * @return The permission data assigned to the specified - * location, or <tt>null</tt> if that location has not been assigned any - * permission data. - * @throws IOException If a failure occurs accessing peristent storage. - */ - public synchronized String[] getPermissionData(String location) throws IOException { - File file; - - if (location == null) { - file = defaultData; - } else { - file = (File) permissionFiles.get(location); - - if (file == null) { - return null; - } - } - - try { - return readData(file); - } catch (FileNotFoundException e) { - return null; - } - } - - /** - * Assigns the specified permission data to the specified - * location. - * - * @param location The location that will be assigned the - * permissions. - * @param data The permission data to be assigned, or <tt>null</tt> - * if the specified location is to be removed from persistent storaqe. - * @throws IOException If a failure occurs modifying peristent storage. - */ - public synchronized void setPermissionData(String location, String[] data) throws IOException { - File file; - - if (location == null) { - file = defaultData; - - if (data == null) { - ReliableFile.delete(defaultData); - } else { - save(defaultData, null, data); /* Save the value in persistent storage */ - } - } else { - file = (File) permissionFiles.get(location); - - if (data == null) { - if (file == null) { - return; - } - - permissionFiles.remove(location); - - ReliableFile.delete(file); - } else { - file = save(file, location, data); /* Save the value in persistent storage */ - - permissionFiles.put(location, file); - } - } - } - - /** - * Load the locations for which permission data exists. - * - * @throws IOException If an error occurs reading the files. - */ - protected void loadLocations() throws IOException { - String list[] = ReliableFile.getBaseFiles(permissionDir); - if (list == null) - return; - int len = list.length; - - for (int i = 0; i < len; i++) { - String name = list[i]; - - if (name.endsWith(ReliableFile.tmpExt)) { - continue; - } - if (name.equals(CONDPERMS)) { - continue; - } - - File file = new File(permissionDir, name); - - try { - String location = readLocation(file); - - if (location != null) { - permissionFiles.put(location, file); - } - } catch (FileNotFoundException e) { - /* the file should have been there */ - } - } - } - - /** - * Read the location from the specified file. - * - * @param file File to read the location from. - * @return Location from the file or null if the file is unknown. - * @throws IOException If an error occurs reading the file. - * @throws FileNotFoundException if the data file does not exist. - */ - private String readLocation(File file) throws IOException { - DataInputStream in = new DataInputStream(new ReliableFileInputStream(file)); - try { - int version = in.readInt(); - - switch (version) { - case PERMISSIONDATA_VERSION_1 : { - boolean locationPresent = in.readBoolean(); - - if (locationPresent) { - String location = in.readUTF(); - - return location; - } - break; - } - default : { - throw new IOException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION); - } - } - } finally { - in.close(); - } - - return null; - } - - /** - * Read the permission data from the specified file. - * - * @param file File to read the permission data from. - * @throws IOException If an error occurs reading the file. - * @throws FileNotFoundException if the data file does not exist. - */ - private String[] readData(File file) throws IOException { - DataInputStream in = new DataInputStream(new ReliableFileInputStream(file)); - try { - int version = in.readInt(); - - switch (version) { - case PERMISSIONDATA_VERSION_1 : { - boolean locationPresent = in.readBoolean(); - - if (locationPresent) { - String location = in.readUTF(); - } - - int size = in.readInt(); - String[] data = new String[size]; - - for (int i = 0; i < size; i++) { - data[i] = in.readUTF(); - } - - return data; - } - default : { - throw new IOException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION); - } - } - } finally { - in.close(); - } - } - - /** - * Save the permission data for the specified location. - * This assumes an attempt has been made to load - * the specified location just prior to calling save. - */ - protected File save(File file, String location, String[] data) throws IOException { - if (file == null) /* we need to create a filename */{ - file = File.createTempFile("perm", "", permissionDir); //$NON-NLS-1$ //$NON-NLS-2$ - file.delete(); /* delete the empty file */ - } - - int size = data.length; - - DataOutputStream out = new DataOutputStream(new ReliableFileOutputStream(file)); - - try { - out.writeInt(PERMISSIONDATA_VERSION); - if (location == null) { - out.writeBoolean(false); - } else { - out.writeBoolean(true); - out.writeUTF(location); - } - out.writeInt(size); - - for (int i = 0; i < size; i++) { - out.writeUTF(data[i]); - } - - } finally { - out.close(); - } - - return file; - } - - public void saveConditionalPermissionInfos(String[] infos) throws IOException { - BufferedWriter writer = null; - try { - writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(permissionDir, CONDPERMS)))); - if (infos == null) - return; - for (int i = 0; i < infos.length; i++) { - writer.write(infos[i]); - writer.newLine(); - } - } finally { - if (writer != null) - writer.close(); - } - } - - public String[] getConditionalPermissionInfos() throws IOException { - BufferedReader reader = null; - ArrayList results = new ArrayList(10); - try { - reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(permissionDir, CONDPERMS)))); - String line; - while ((line = reader.readLine()) != null) - if (line.length() != 0) - results.add(line); - } catch (FileNotFoundException e) { - // do nothing return empty vector - } catch (IOException e) { - throw e; - } catch (Exception e) { - throw new IOException(e.getMessage()); - } finally { - if (reader != null) - reader.close(); - } - return results.size() == 0 ? null : (String[]) results.toArray(new String[results.size()]); - } -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultAdaptor.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultAdaptor.java deleted file mode 100644 index 7d607c4a6..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultAdaptor.java +++ /dev/null @@ -1,203 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2005 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.defaultadaptor; - -import java.io.File; -import java.io.IOException; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import org.eclipse.osgi.framework.adaptor.BundleData; -import org.eclipse.osgi.framework.adaptor.core.*; -import org.eclipse.osgi.framework.debug.Debug; -import org.eclipse.osgi.framework.log.FrameworkLog; -import org.osgi.framework.BundleException; -import org.osgi.framework.FrameworkEvent; - -/** - * The DefaultAdaptor for the Framework. This adaptor uses - * root bundle store directory on the local filesystem to - * store bundle files and bundle data. - * <p> - * Each bundle installed in the Framework will have a unique - * directory using the bundle ID as the name. Each bundles - * unique directory has a generational directory a data directory - * and a metadata file. - * <p> - * The generational directory is used to store the different - * versions of the bundle that have been installed. Each time - * the bundle is updated a new generational directory will be - * created. - * <p> - * The data directory is used to create data file objects requested - * by the bundle. This directory will not change when updating - * a bundle - * <p> - * The metadata file contains persistent data about the bundle - * (e.g. startlevel, persistent start state, etc) - */ -public class DefaultAdaptor extends AbstractFrameworkAdaptor { - public static final String METADATA_ADAPTOR_NEXTID = "METADATA_ADAPTOR_NEXTID"; //$NON-NLS-1$ - public static final String METADATA_ADAPTOR_IBSL = "METADATA_ADAPTOR_IBSL"; //$NON-NLS-1$ - - public static final String METADATA_BUNDLE_GEN = "METADATA_BUNDLE_GEN"; //$NON-NLS-1$ - public static final String METADATA_BUNDLE_LOC = "METADATA_BUNDLE_LOC"; //$NON-NLS-1$ - public static final String METADATA_BUNDLE_REF = "METADATA_BUNDLE_REF"; //$NON-NLS-1$ - public static final String METADATA_BUNDLE_NAME = "METADATA_BUNDLE_NAME"; //$NON-NLS-1$ - public static final String METADATA_BUNDLE_NCP = "METADATA_BUNDLE_NCP"; //$NON-NLS-1$ - public static final String METADATA_BUNDLE_ABSL = "METADATA_BUNDLE_ABSL"; //$NON-NLS-1$ - public static final String METADATA_BUNDLE_STATUS = "METADATA_BUNDLE_STATUS"; //$NON-NLS-1$ - public static final String METADATA_BUNDLE_METADATA = "METADATA_BUNDLE_METADATA"; //$NON-NLS-1$ - public static final String METADATA_LAST_MODIFIED = "METADATA_LAST_MODIFIED"; //$NON-NLS-1$ - - /** - * The MetaData for the default adaptor - */ - protected MetaData fwMetadata; - - public DefaultAdaptor(String[] args) { - super(args); - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getInstalledBundles() - */ - public BundleData[] getInstalledBundles() { - String list[] = getBundleStoreRootDir().list(); - - if (list == null) { - return null; - } - ArrayList bundleDatas = new ArrayList(list.length); - - /* create bundle objects for all installed bundles. */ - for (int i = 0; i < list.length; i++) { - try { - DefaultBundleData data; - - long id = -1; - try { - id = Long.parseLong(list[i]); - } catch (NumberFormatException nfe) { - continue; - } - data = (DefaultBundleData) getElementFactory().createBundleData(this, id); - loadMetaDataFor(data); - data.initializeExistingBundle(); - - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("BundleData created: " + data); //$NON-NLS-1$ - } - processExtension(data, EXTENSION_INITIALIZE); - bundleDatas.add(data); - } catch (BundleException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to open Bundle[" + list[i] + "]: " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ - Debug.printStackTrace(e); - } - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to open Bundle[" + list[i] + "]: " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ - Debug.printStackTrace(e); - } - } - } - - return (BundleData[]) bundleDatas.toArray(new BundleData[bundleDatas.size()]); - } - - public void setInitialBundleStartLevel(int value) { - super.setInitialBundleStartLevel(value); - try { - persistInitialBundleStartLevel(value); - } catch (IOException e) { - eventPublisher.publishFrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e); - } - } - - protected void persistInitialBundleStartLevel(int value) throws IOException { - fwMetadata.setInt(METADATA_ADAPTOR_IBSL, value); - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - fwMetadata.save(); - return null; - } - }); - } catch (PrivilegedActionException e) { - if (e.getException() instanceof IOException) { - throw (IOException)e.getException(); - } - throw (RuntimeException)e.getException(); - } - } - - public AdaptorElementFactory getElementFactory() { - if (elementFactory == null) - elementFactory = new DefaultElementFactory(); - return elementFactory; - } - - protected void loadMetaDataFor(DefaultBundleData data) throws IOException { - MetaData bundleMetaData = (new MetaData(new File(data.getBundleStoreDir(), ".bundle"), "Bundle metadata")); //$NON-NLS-1$ //$NON-NLS-2$ - bundleMetaData.load(); - - data.setLocation(bundleMetaData.get(METADATA_BUNDLE_LOC, null)); - data.setFileName(bundleMetaData.get(METADATA_BUNDLE_NAME, null)); - data.setGeneration(bundleMetaData.getInt(METADATA_BUNDLE_GEN, -1)); - data.setNativePaths(bundleMetaData.get(METADATA_BUNDLE_NCP, null)); - data.setStartLevel(bundleMetaData.getInt(METADATA_BUNDLE_ABSL, 1)); - data.setStatus(bundleMetaData.getInt(METADATA_BUNDLE_STATUS, 0)); - data.setReference(bundleMetaData.getBoolean(METADATA_BUNDLE_REF, false)); - data.setLastModified(bundleMetaData.getLong(METADATA_LAST_MODIFIED, 0)); - - if (data.getGeneration() == -1 || data.getFileName() == null || data.getLocation() == null) { - throw new IOException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION); - } - } - - public void saveMetaDataFor(AbstractBundleData data) throws IOException { - MetaData bundleMetadata = (new MetaData(new File(((DefaultBundleData) data).createBundleStoreDir(), ".bundle"), "Bundle metadata")); //$NON-NLS-1$ //$NON-NLS-2$ - bundleMetadata.load(); - - bundleMetadata.set(METADATA_BUNDLE_LOC, data.getLocation()); - bundleMetadata.set(METADATA_BUNDLE_NAME, data.getFileName()); - bundleMetadata.setInt(METADATA_BUNDLE_GEN, data.getGeneration()); - String nativePaths = data.getNativePathsString(); - if (nativePaths != null) { - bundleMetadata.set(METADATA_BUNDLE_NCP, nativePaths); - } - bundleMetadata.setInt(METADATA_BUNDLE_ABSL, data.getStartLevel()); - bundleMetadata.setInt(METADATA_BUNDLE_STATUS, data.getStatus()); - bundleMetadata.setBoolean(METADATA_BUNDLE_REF, data.isReference()); - bundleMetadata.setLong(METADATA_LAST_MODIFIED, data.getLastModified()); - - bundleMetadata.save(); - } - - protected void persistNextBundleID(long id) throws IOException { - fwMetadata.setLong(METADATA_ADAPTOR_NEXTID, nextId); - fwMetadata.save(); - } - - protected void initializeMetadata() throws IOException { - fwMetadata = new MetaData(getMetaDataFile(), "Framework metadata"); //$NON-NLS-1$ - fwMetadata.load(); - nextId = fwMetadata.getLong(METADATA_ADAPTOR_NEXTID, 1); - initialBundleStartLevel = fwMetadata.getInt(METADATA_ADAPTOR_IBSL, 1); - } - - protected FrameworkLog createFrameworkLog() { - return new DefaultLog(); - } -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultBundleData.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultBundleData.java deleted file mode 100644 index c88eb3b12..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultBundleData.java +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2005 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.defaultadaptor; - -import java.io.File; -import java.io.IOException; -import org.eclipse.osgi.framework.adaptor.core.AbstractBundleData; -import org.eclipse.osgi.framework.debug.Debug; -import org.osgi.framework.BundleException; - -/** - * The <code>BundleData</code> represents a single bundle that is persistently - * stored by a <code>FrameworkAdaptor</code>. A <code>BundleData</code> creates - * the ClassLoader for a bundle, finds native libraries installed in the - * FrameworkAdaptor for the bundle, creates data files for the bundle, - * used to access bundle entries, manifest information, and getting and saving - * metadata. - * - */ -public class DefaultBundleData extends AbstractBundleData { - /** - * Read data from an existing directory. - * This constructor is used by getInstalledBundles. - * - * @throws NumberFormatException if the directory is not a - * number, the directory contains a ".delete" file or - * the directory does not contain a ".bundle" file. - * @throws IOException If an error occurs initializing the bundle data. - */ - public void initializeExistingBundle() throws BundleException, IOException { - File delete = new File(getBundleStoreDir(), ".delete"); //$NON-NLS-1$ - - /* and the directory is not marked for delete */ - if (delete.exists()) - throw new IOException(); - - createBaseBundleFile(); - - loadFromManifest(); - } - - /** - * Constructs a DefaultBundleData for the DefaultAdaptor. - * - * @param adaptor the DefaultAdaptor for this DefaultBundleData - * @param id the Bundle ID for this DefaultBundleData - */ - public DefaultBundleData(DefaultAdaptor adaptor, long id) { - super(adaptor, id); - } - - public String toString() { - return getLocation(); - } - - /** - * Save the bundle data in the data file. - * - * @throws IOException if a write error occurs. - */ - public synchronized void save() throws IOException { - if (adaptor.canWrite()) - ((DefaultAdaptor) adaptor).saveMetaDataFor(this); - } - - /** - * Return the top level bundle directory. - * - * @return Top level bundle directory. - */ - protected File createBundleStoreDir() { - if (!getBundleStoreDir().exists() && !getBundleStoreDir().mkdirs()) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Unable to create bundle store directory: " + getBundleStoreDir().getPath()); //$NON-NLS-1$ - } - } - return getBundleStoreDir(); - } - -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultElementFactory.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultElementFactory.java deleted file mode 100644 index 87644a6b4..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultElementFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2005 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.defaultadaptor; - -import java.io.IOException; - -import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain; -import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; -import org.eclipse.osgi.framework.adaptor.core.*; - -public class DefaultElementFactory implements AdaptorElementFactory { - - public AbstractBundleData createBundleData(AbstractFrameworkAdaptor adaptor, long id) throws IOException { - return new DefaultBundleData((DefaultAdaptor) adaptor, id); - } - - public org.eclipse.osgi.framework.adaptor.BundleClassLoader createClassLoader(ClassLoaderDelegate delegate, BundleProtectionDomain domain, String[] bundleclasspath, AbstractBundleData data) { - return new DefaultClassLoader(delegate, domain, bundleclasspath, data.getAdaptor().getBundleClassLoaderParent(), data); - } - -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultLog.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultLog.java deleted file mode 100644 index dd1d027aa..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/DefaultLog.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004 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.defaultadaptor; - -import java.io.*; -import org.eclipse.osgi.framework.log.FrameworkLog; -import org.eclipse.osgi.framework.log.FrameworkLogEntry; -import org.osgi.framework.FrameworkEvent; - -/* - * This is an empty implementation that does no actually logging. - */ -public class DefaultLog implements FrameworkLog { - - public DefaultLog() { - } - - public void log(FrameworkEvent frameworkEvent) { - } - - public void log(FrameworkLogEntry logEntry) { - } - - public void setWriter(Writer newWriter, boolean append) { - } - - public void setFile(File newFile, boolean append) throws IOException { - } - - public File getFile() { - return null; - } - - public void setConsoleLog(boolean consoleLog) { - } - - public void close() { - } - -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/MetaData.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/MetaData.java deleted file mode 100644 index 60dee03dc..000000000 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/defaultadaptor/MetaData.java +++ /dev/null @@ -1,201 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2005 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.defaultadaptor; - -import java.io.*; -import java.util.Properties; - -/** - * This class uses a Properties object to store and get MetaData information. - * All data is converted into String data before saving. - */ -public class MetaData { - - /** - * The Properties file to store the data. - */ - Properties properties = new Properties(); - - /** - * The File object to store and load the Properties object. - */ - File datafile; - - /** - * The header string to use when storing data to the datafile. - */ - String header; - - /** - * Constructs a MetaData object that uses the datafile to persistently - * store data. - * @param datafile The File object used to persistently load and store data. - * @param header The header to use when storing data persistently. - */ - public MetaData(File datafile, String header) { - this.datafile = datafile; - this.header = header; - } - - /** - * Gets the metadata value for the key. - * @param key the key of the metadata - * @param def the default value to return if the key does not exist - * @return the value of the metadata or null if the key does not exist - * and the specified default is null. - */ - public String get(String key, String def) { - return properties.getProperty(key, def); - } - - /** - * Gets the integer value for the key. - * @param key the key of the metadata - * @param def the default value to return if the key does not exist - * @return the value of the metadata; if the key does not exist or - * the value cannot be converted to an int value then the - * specified default value is returned. - */ - public int getInt(String key, int def) { - String result = get(key, null); - if (result == null) { - return def; - } - try { - return Integer.parseInt(result); - } catch (NumberFormatException nfe) { - return def; - } - } - - /** - * Gets the long value for the key. - * @param key the key of the metadata - * @param def the default value to return if the key does not exist - * @return the value of the metadata; if the key does not exist or - * the value cannot be converted to an long value then the - * specified default value is returned. - */ - public long getLong(String key, long def) { - String result = get(key, null); - if (result == null) { - return def; - } - try { - return Long.parseLong(result); - } catch (NumberFormatException nfe) { - return def; - } - } - - /** - * Gets the boolean value for the key. - * @param key the key of the metadata - * @param def the default value to return if the key does not exist - * @return the value of the metadata; if the key does not exist then the - * specified default value is returned. - */ - public boolean getBoolean(String key, boolean def) { - String result = get(key, null); - if (result == null) { - return def; - } - return Boolean.valueOf(result).booleanValue(); - } - - /** - * Sets the String value for a key. - * @param key the key of the metadata - * @param val the value of the metadata - */ - public void set(String key, String val) { - properties.put(key, val); - } - - /** - * Sets the int value for a key. - * @param key the key of the metadata - * @param val the value of the metadata - */ - public void setInt(String key, int val) { - properties.put(key, Integer.toString(val)); - } - - /** - * Sets the long value for a key. - * @param key the key of the metadata - * @param val the value of the metadata - */ - public void setLong(String key, long val) { - properties.put(key, Long.toString(val)); - } - - /** - * Sets the boolean value for a key. - * @param key the key of the metadata - * @param val the value of the metadata - */ - public void setBoolean(String key, boolean val) { - properties.put(key, (val ? Boolean.TRUE : Boolean.FALSE).toString()); - } - - /** - * Removes the metadata value with the specified key. - * @param key the key of the metadata to be removed - */ - public void remove(String key) { - properties.remove(key); - } - - /** - * Saves the metadata to persistent storage. - * @throws IOException if there is a problem saving to persistent storage. - */ - public void save() throws IOException { - if (!datafile.exists() && datafile.getParent() != null) { - File parent = new File(datafile.getParent()); - if (!parent.exists()) - parent.mkdir(); - } - - FileOutputStream fos = new FileOutputStream(datafile); - try { - properties.store(fos, header); - } finally { - fos.close(); - } - } - - /** - * Loads the metadata from persistent storage - * @throws IOException if there is a problem reading from persistent storage. - */ - public void load() throws IOException { - properties.clear(); - if (datafile.exists()) { - FileInputStream fis = new FileInputStream(datafile); - try { - properties.load(fis); - } finally { - fis.close(); - } - } - } - - /** - * @see Object#toString() - */ - public String toString() { - return properties.toString(); - } - -} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundleentry/Handler.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundleentry/Handler.java index 2bf25fbc3..61c09995e 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundleentry/Handler.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundleentry/Handler.java @@ -14,9 +14,9 @@ package org.eclipse.osgi.framework.internal.protocol.bundleentry; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; -import org.eclipse.osgi.framework.adaptor.core.*; -import org.eclipse.osgi.framework.internal.core.AbstractBundle; -import org.eclipse.osgi.framework.internal.core.BundleResourceHandler; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.framework.internal.core.*; /** * URLStreamHandler the bundleentry protocol. @@ -36,8 +36,8 @@ public class Handler extends BundleResourceHandler { } protected BundleEntry findBundleEntry(URL url, AbstractBundle bundle) throws IOException { - AbstractBundleData bundleData = (AbstractBundleData) bundle.getBundleData(); - BundleEntry entry = bundleData.getBaseBundleFile().getEntry(url.getPath()); + BaseData bundleData = (BaseData) bundle.getBundleData(); + BundleEntry entry = bundleData.getBundleFile().getEntry(url.getPath()); if (entry == null) throw new FileNotFoundException(url.getPath()); return entry; diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundleresource/Handler.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundleresource/Handler.java index af29b5743..1c0b64c45 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundleresource/Handler.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/protocol/bundleresource/Handler.java @@ -15,10 +15,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.util.Enumeration; -import org.eclipse.osgi.framework.adaptor.core.*; -import org.eclipse.osgi.framework.adaptor.core.BundleEntry; -import org.eclipse.osgi.framework.internal.core.*; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.loader.BaseClassLoader; +import org.eclipse.osgi.baseadaptor.loader.ClasspathManager; import org.eclipse.osgi.framework.internal.core.AbstractBundle; +import org.eclipse.osgi.framework.internal.core.BundleResourceHandler; /** * URLStreamHandler the bundleresource protocol. @@ -38,16 +39,16 @@ public class Handler extends BundleResourceHandler { } protected BundleEntry findBundleEntry(URL url, AbstractBundle bundle) throws IOException { - AbstractClassLoader cl = (AbstractClassLoader) getBundleClassLoader(bundle); - if (cl== null) + BaseClassLoader classloader = getBundleClassLoader(bundle); + if (classloader == null) throw new FileNotFoundException(url.getPath()); + ClasspathManager cpManager = classloader.getClasspathManager(); int index = url.getPort(); BundleEntry entry = null; if (index == 0) { - entry = (BundleEntry) cl.findLocalObject(url.getPath()); - } - else { - Enumeration entries = cl.findLocalObjects(url.getPath()); + entry = cpManager.findLocalEntry(url.getPath()); + } else { + Enumeration entries = cpManager.findLocalEntries(url.getPath()); if (entries != null) for (int i = 0; entries.hasMoreElements() && i <= index; i++) entry = (BundleEntry) entries.nextElement(); @@ -58,4 +59,3 @@ public class Handler extends BundleResourceHandler { } } - diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java index a03cc3e83..0321479b0 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java @@ -501,6 +501,7 @@ public class ReliableFile { * Answers a boolean indicating whether or not the specified reliable file * exists on the underlying file system. This call only returns if a file * exists and not if the file contents are valid. + * @param file returns true if the specified reliable file exists; otherwise false is returned * * @return <code>true</code> if the specified reliable file exists, * <code>false</code> otherwise. @@ -573,6 +574,7 @@ public class ReliableFile { /** * Delete the specified reliable file on the underlying file system. + * @param deleteFile the reliable file to delete * * @return <code>true</code> if the specified reliable file was deleted, * <code>false</code> otherwise. diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java index c817fda06..e1dffe8a4 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java @@ -120,6 +120,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default FilterInputStream method. + * @see FilterInputStream#read(byte[], int, int) */ public synchronized int read(byte b[], int off, int len) throws IOException { if (readPos >= length) { @@ -138,6 +139,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default FilterInputStream method. + * @see FilterInputStream#read(byte[]) */ public synchronized int read(byte b[]) throws IOException { return read(b, 0, b.length); @@ -145,6 +147,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default FilterInputStream method. + * @see FilterInputStream#read() */ public synchronized int read() throws IOException { if (readPos >= length) { @@ -160,6 +163,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default available method. + * @see FilterInputStream#available() */ public synchronized int available() throws IOException { if (readPos < length) // just in case @@ -169,6 +173,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default skip method. + * @see FilterInputStream#skip(long) */ public synchronized long skip(long n) throws IOException { long len = super.skip(n); @@ -180,6 +185,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default markSupported method. + * @see FilterInputStream#markSupported() */ public boolean markSupported() { return false; @@ -187,6 +193,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default mark method. + * @see FilterInputStream#mark(int) */ public void mark(int readlimit) { //ignore @@ -194,6 +201,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default reset method. + * @see FilterInputStream#reset() */ public void reset() throws IOException { throw new IOException("reset not supported."); //$NON-NLS-1$ diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java index a67f88f54..3c2a3a099 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java @@ -142,6 +142,7 @@ public class ReliableFileOutputStream extends FilterOutputStream { /** * Override default FilterOutputStream method. + * @see FilterOutputStream#write(byte[]) */ public void write(byte[] b) throws IOException { this.write(b, 0, b.length); @@ -149,6 +150,7 @@ public class ReliableFileOutputStream extends FilterOutputStream { /** * Override default FilterOutputStream method. + * @see FilterOutputStream#write(byte[], int, int) */ public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); @@ -157,6 +159,7 @@ public class ReliableFileOutputStream extends FilterOutputStream { /** * Override default FilterOutputStream method. + * @see FilterOutputStream#write(int) */ public void write(int b) throws IOException { out.write(b); diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AdaptorMsg.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/AdaptorMsg.java index d5a71a06f..a2c519ecb 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/AdaptorMsg.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/AdaptorMsg.java @@ -8,7 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ -package org.eclipse.osgi.framework.adaptor.core; +package org.eclipse.osgi.internal.baseadaptor; import org.eclipse.osgi.util.NLS; @@ -49,7 +49,7 @@ public class AdaptorMsg extends NLS { public static String URL_NO_BUNDLE_FOUND; public static String URL_NO_BUNDLE_ID; - private static final String BUNDLE_NAME = "org.eclipse.osgi.framework.adaptor.core.ExternalMessages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = "org.eclipse.osgi.internal.baseadaptor.ExternalMessages"; //$NON-NLS-1$ static { // initialize resource bundles diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/AdaptorUtil.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/AdaptorUtil.java new file mode 100644 index 000000000..0c6f89c85 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/AdaptorUtil.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2005 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.internal.baseadaptor; + +import java.io.*; +import java.net.URL; +import java.util.Dictionary; +import java.util.Hashtable; +import org.eclipse.core.runtime.internal.adaptor.EclipseAdaptorMsg; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.util.Headers; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.*; + +/** + * A utility class with some generally useful static methods for adaptor hook implementations + */ +public class AdaptorUtil { + /** The NULL tag used in bundle storage */ + public static final byte NULL = 0; + /** The OBJECT tag used in bundle storage */ + public static final byte OBJECT = 1; + + /** + * Does a recursive copy of one directory to another. + * @param inDir input directory to copy. + * @param outDir output directory to copy to. + * @throws IOException if any error occurs during the copy. + */ + public static void copyDir(File inDir, File outDir) throws IOException { + String[] files = inDir.list(); + if (files != null && files.length > 0) { + outDir.mkdir(); + for (int i = 0; i < files.length; i++) { + File inFile = new File(inDir, files[i]); + File outFile = new File(outDir, files[i]); + if (inFile.isDirectory()) { + copyDir(inFile, outFile); + } else { + InputStream in = new FileInputStream(inFile); + readFile(in, outFile); + } + } + } + } + + /** + * Read a file from an InputStream and write it to the file system. + * + * @param in InputStream from which to read. + * @param file output file to create. + * @exception IOException + */ + public static void readFile(InputStream in, File file) throws IOException { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file); + + byte buffer[] = new byte[1024]; + int count; + while ((count = in.read(buffer, 0, buffer.length)) > 0) { + fos.write(buffer, 0, count); + } + + fos.close(); + fos = null; + + in.close(); + in = null; + } catch (IOException e) { + // close open streams + if (fos != null) { + try { + fos.close(); + } catch (IOException ee) { + // nothing to do here + } + } + + if (in != null) { + try { + in.close(); + } catch (IOException ee) { + // nothing to do here + } + } + + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + Debug.println("Unable to read file"); //$NON-NLS-1$ + Debug.printStackTrace(e); + } + + throw e; + } + } + + /** + * This function performs the equivalent of "rm -r" on a file or directory. + * + * @param file file or directory to delete + * @return false is the specified files still exists, true otherwise. + */ + public static boolean rm(File file) { + if (file.exists()) { + if (file.isDirectory()) { + String list[] = file.list(); + if (list != null) { + int len = list.length; + for (int i = 0; i < len; i++) { + // we are doing a lot of garbage collecting here + rm(new File(file, list[i])); + } + } + } + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + if (file.isDirectory()) { + Debug.println("rmdir " + file.getPath()); //$NON-NLS-1$ + } else { + Debug.println("rm " + file.getPath()); //$NON-NLS-1$ + } + } + + boolean success = file.delete(); + + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + if (!success) { + Debug.println(" rm failed!!"); //$NON-NLS-1$ + } + } + + return (success); + } + return (true); + } + + public static String readString(DataInputStream in, boolean intern) throws IOException { + byte type = in.readByte(); + if (type == NULL) + return null; + return intern ? in.readUTF().intern() : in.readUTF(); + } + + public static void writeStringOrNull(DataOutputStream out, String string) throws IOException { + if (string == null) + out.writeByte(NULL); + else { + out.writeByte(OBJECT); + out.writeUTF(string); + } + } + + public static Version loadVersion(DataInputStream in) throws IOException { + String versionString = readString(in, false); + try { + return Version.parseVersion(versionString); + } catch (IllegalArgumentException e) { + return new InvalidVersion(versionString); + } + } + + /** + * Register a service object. + * @param name the service class name + * @param service the service object + * @param context the registering bundle context + * @return the service registration object + */ + public static ServiceRegistration register(String name, Object service, BundleContext context) { + Hashtable properties = new Hashtable(7); + Dictionary headers = context.getBundle().getHeaders(); + properties.put(Constants.SERVICE_VENDOR, headers.get(Constants.BUNDLE_VENDOR)); + properties.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE)); + properties.put(Constants.SERVICE_PID, context.getBundle().getBundleId() + "." + service.getClass().getName()); //$NON-NLS-1$ + return context.registerService(name, service, properties); + } + + public static Dictionary loadManifestFrom(BaseData bundledata) throws BundleException { + URL url = bundledata.getEntry(Constants.OSGI_BUNDLE_MANIFEST); + if (url == null) + return null; + try { + return Headers.parseManifest(url.openStream()); + } catch (IOException e) { + throw new BundleException(NLS.bind(EclipseAdaptorMsg.ECLIPSE_DATA_ERROR_READING_MANIFEST, bundledata.getLocation()), e); + } + } + +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseClassLoadingHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseClassLoadingHook.java new file mode 100644 index 000000000..d752d20af --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseClassLoadingHook.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.internal.baseadaptor; + +import java.io.File; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook; +import org.eclipse.osgi.baseadaptor.loader.*; +import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain; +import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; +import org.eclipse.osgi.framework.debug.Debug; + +public class BaseClassLoadingHook implements ClassLoadingHook { + + public String findLibrary(BaseData data, String libName) { + String mappedName = System.mapLibraryName(libName); + String path = null; + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println(" mapped library name: " + mappedName); //$NON-NLS-1$ + path = findNativePath(data, mappedName); + if (path == null) { + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println(" library does not exist: " + mappedName); //$NON-NLS-1$ + path = findNativePath(data, libName); + } + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println(" returning library: " + path); //$NON-NLS-1$ + return path; + } + + private String findNativePath(BaseData bundledata, String libname) { + int slash = libname.lastIndexOf('/'); + if (slash >= 0) + libname = libname.substring(slash + 1); + String[] nativepaths = getNativePaths(bundledata); + if (nativepaths == null) + return null; + for (int i = 0; i < nativepaths.length; i++) { + slash = nativepaths[i].lastIndexOf('/'); + String path = slash < 0 ? nativepaths[i] : nativepaths[i].substring(slash + 1); + if (path.equals(libname)) { + File nativeFile = bundledata.getBundleFile().getFile(nativepaths[i], true); + if (nativeFile != null) + return nativeFile.getAbsolutePath(); + } + } + return null; + } + + private String[] getNativePaths(BaseData bundledata) { + BaseStorageHook storageHook = (BaseStorageHook) bundledata.getStorageHook(BaseStorageHook.KEY); + return storageHook != null ? storageHook.getNativePaths() : null; + } + + public boolean addClassPathEntry(ArrayList cpEntries, String cp, ClasspathManager hostmanager, BaseData sourcedata, ProtectionDomain sourcedomain) { + // do nothing + return false; + } + + public ClassLoader getBundleClassLoaderParent() { + // do nothing + return null; + } + + public byte[] processClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { + // do nothing + return null; + } + + public BaseClassLoader createClassLoader(ClassLoader parent, ClassLoaderDelegate delegate, BundleProtectionDomain domain, BaseData data, String[] bundleclasspath) { + // do nothing + return null; + } + + public void initializedClassLoader(BaseClassLoader baseClassLoader, BaseData data) { + // do nothing + } + +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseHookConfigurator.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseHookConfigurator.java new file mode 100644 index 000000000..abcc816fd --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseHookConfigurator.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2006 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.internal.baseadaptor; + +import org.eclipse.osgi.baseadaptor.HookConfigurator; +import org.eclipse.osgi.baseadaptor.HookRegistry; + +/** + * Add the hooks necessary to support the OSGi Framework specification. + */ +public class BaseHookConfigurator implements HookConfigurator { + + public void addHooks(HookRegistry registry) { + // always add the BaseStorageHook and BaseClassLoadingHook; it is required for the storage implementation + registry.addStorageHook(new BaseStorageHook(BaseStorage.getInstance())); + registry.addClassLoadingHook(new BaseClassLoadingHook()); + } + +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BasePermissionStorage.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BasePermissionStorage.java new file mode 100644 index 000000000..c0deb55c1 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BasePermissionStorage.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.internal.baseadaptor; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import org.eclipse.osgi.framework.adaptor.PermissionStorage; + +public class BasePermissionStorage implements PermissionStorage { + + private HashMap locations = new HashMap(); + private String[] defaultInfos; + private String[] condPermInfos; + private BaseStorage storage; + private boolean dirty; + + BasePermissionStorage(BaseStorage storage) { + this.storage = storage; + } + + public String[] getLocations() throws IOException { + synchronized (locations) { + String[] result = new String[locations.size()]; + int i = 0; + for (Iterator iLocs = locations.keySet().iterator(); iLocs.hasNext(); i++) + result[i] = (String) iLocs.next(); + return result; + } + } + + public String[] getPermissionData(String location) throws IOException { + if (location == null) + return defaultInfos; + synchronized (locations) { + if (locations.size() == 0) + return null; + return (String[]) locations.get(location); + } + } + + public void setPermissionData(String location, String[] data) throws IOException { + if (location == null) { + defaultInfos = data; + return; + } + synchronized (locations) { + if (data == null) + locations.remove(location); + else + locations.put(location, data); + } + setDirty(true); + storage.requestSave(); + } + + public void saveConditionalPermissionInfos(String[] infos) throws IOException { + condPermInfos = infos; + setDirty(true); + storage.requestSave(); + } + + public String[] getConditionalPermissionInfos() throws IOException { + return condPermInfos; + } + + public boolean isDirty() { + return dirty; + } + + public void setDirty(boolean dirty) { + this.dirty = dirty; + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java new file mode 100644 index 000000000..814c556f9 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorage.java @@ -0,0 +1,1111 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.internal.baseadaptor; + +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.*; +import java.util.*; +import org.eclipse.core.runtime.adaptor.EclipseStarter; +import org.eclipse.core.runtime.adaptor.LocationManager; +import org.eclipse.core.runtime.internal.adaptor.EclipseAdaptorMsg; +import org.eclipse.osgi.baseadaptor.BaseAdaptor; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.baseadaptor.bundlefile.*; +import org.eclipse.osgi.baseadaptor.hooks.BundleFileFactoryHook; +import org.eclipse.osgi.baseadaptor.hooks.StorageHook; +import org.eclipse.osgi.framework.adaptor.*; +import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.framework.debug.FrameworkDebugOptions; +import org.eclipse.osgi.framework.internal.core.*; +import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.log.FrameworkLogEntry; +import org.eclipse.osgi.framework.util.KeyedHashSet; +import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.osgi.service.resolver.*; +import org.eclipse.osgi.storagemanager.ManagedOutputStream; +import org.eclipse.osgi.storagemanager.StorageManager; +import org.eclipse.osgi.util.ManifestElement; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.*; + +public class BaseStorage { + private static final String RUNTIME_ADAPTOR = FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + "/eclipseadaptor"; //$NON-NLS-1$ + private static final String OPTION_PLATFORM_ADMIN = RUNTIME_ADAPTOR + "/debug/platformadmin"; //$NON-NLS-1$ + private static final String OPTION_PLATFORM_ADMIN_RESOLVER = RUNTIME_ADAPTOR + "/debug/platformadmin/resolver"; //$NON-NLS-1$ + private static final String OPTION_MONITOR_PLATFORM_ADMIN = RUNTIME_ADAPTOR + "/resolver/timing"; //$NON-NLS-1$ + private static final String OPTION_RESOLVER_READER = RUNTIME_ADAPTOR + "/resolver/reader/timing"; //$NON-NLS-1$ + private static final String PROP_FRAMEWORK_EXTENSIONS = "osgi.framework.extensions"; //$NON-NLS-1$ + private static final String PROP_BUNDLE_STORE = "osgi.bundlestore"; //$NON-NLS-1$ + // The name of the bundle data directory + static final String DATA_DIR_NAME = "data"; //$NON-NLS-1$ + // System property used to determine whether State saver needs to be enabled + private static final String PROP_ENABLE_STATE_SAVER = "eclipse.enableStateSaver"; //$NON-NLS-1$ + static final String BUNDLEFILE_NAME = "bundlefile"; //$NON-NLS-1$ + // System property used to clean the osgi configuration area + private static final String PROP_CLEAN = "osgi.clean"; //$NON-NLS-1$ + + /** The current bundle data version */ + public static final byte BUNDLEDATA_VERSION = 18; + /** + * flag to indicate a framework extension is being intialized + */ + public static final byte EXTENSION_INITIALIZE = 0x01; + /** + * flag to indicate a framework extension is being installed + */ + public static final byte EXTENSION_INSTALLED = 0x02; + /** + * flag to indicate a framework extension is being uninstalled + */ + public static final byte EXTENSION_UNINSTALLED = 0x04; + /** + * flag to indicate a framework extension is being updated + */ + public static final byte EXTENSION_UPDATED = 0x08; + private static final String PERM_DATA_FILE = ".permdata"; //$NON-NLS-1$ + private static final byte PERMDATA_VERSION = 1; + + private static final BaseStorage INSTANCE = new BaseStorage(); + + private BaseAdaptor adaptor; + // assume a file: installURL + private String installPath; + private StorageManager storageManager; + private StateManager stateManager; + // no need to synchronize on storageHooks because the elements are statically set in initialize + private KeyedHashSet storageHooks = new KeyedHashSet(5, false); + private BundleContext context; + /** + * The add URL method used to support framework extensions + */ + private Method addURLMethod; + /** + * The list of configured framework extensions + */ + private String[] configuredExtensions; + + private long timeStamp = 0; + private int initialBundleStartLevel = 1; + private long nextId = 1; + /** + * directory containing installed bundles + */ + private File bundleStoreRoot; + + private BasePermissionStorage permissionStorage; + private StateSaver stateSaver; + private boolean invalidState; + + private BaseStorage() { + // make constructor private + } + + public void initialize(BaseAdaptor adaptor) throws IOException { + this.adaptor = adaptor; + setDebugOptions(); + if (Boolean.valueOf(FrameworkProperties.getProperty(BaseStorage.PROP_CLEAN)).booleanValue()) + cleanOSGiCache(); + // initialize the addURLMethod to support framework extensions + ClassLoader fwloader = BaseStorage.class.getClassLoader(); + if (fwloader != null) + addURLMethod = findaddURLMethod(fwloader.getClass()); + // we need to set the install path as soon as possible so we can determine + // the absolute location of install relative URLs + Location installLoc = LocationManager.getInstallLocation(); + if (installLoc != null) { + URL installURL = installLoc.getURL(); + // assume install URL is file: based + installPath = installURL.getPath(); + } + boolean readOnlyConfiguration = LocationManager.getConfigurationLocation().isReadOnly(); + storageManager = initFileManager(LocationManager.getOSGiConfigurationDir(), readOnlyConfiguration ? "none" : null, readOnlyConfiguration); //$NON-NLS-1$ + // initialize the storageHooks + StorageHook[] hooks = adaptor.getHookRegistry().getStorageHooks(); + for (int i = 0; i < hooks.length; i++) + storageHooks.add(hooks[i]); + } + + private void setDebugOptions() { + FrameworkDebugOptions options = FrameworkDebugOptions.getDefault(); + // may be null if debugging is not enabled + if (options == null) + return; + StateManager.DEBUG = options != null; + StateManager.DEBUG_READER = options.getBooleanOption(OPTION_RESOLVER_READER, false); + StateManager.MONITOR_PLATFORM_ADMIN = options.getBooleanOption(OPTION_MONITOR_PLATFORM_ADMIN, false); + StateManager.DEBUG_PLATFORM_ADMIN = options.getBooleanOption(OPTION_PLATFORM_ADMIN, false); + StateManager.DEBUG_PLATFORM_ADMIN_RESOLVER = options.getBooleanOption(OPTION_PLATFORM_ADMIN_RESOLVER, false); + } + + protected StorageManager initFileManager(File baseDir, String lockMode, boolean readOnly) { + StorageManager sManager = new StorageManager(baseDir, lockMode, readOnly); + try { + sManager.open(!readOnly); + } catch (IOException ex) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + Debug.println("Error reading framework metadata: " + ex.getMessage()); //$NON-NLS-1$ + Debug.printStackTrace(ex); + } + String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FILEMANAGER_OPEN_ERROR, ex.getMessage()); + FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, ex, null); + adaptor.getFrameworkLog().log(logEntry); + } + return sManager; + } + + public boolean isReadOnly() { + return storageManager.isReadOnly(); + } + + public void compact() throws IOException { + if (!isReadOnly()) + compact(getBundleStoreRoot()); + } + + private void compact(File directory) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("compact(" + directory.getPath() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + String list[] = directory.list(); + if (list == null) + return; + + int len = list.length; + for (int i = 0; i < len; i++) { + if (BaseStorage.DATA_DIR_NAME.equals(list[i])) + continue; /* do not examine the bundles data dir. */ + File target = new File(directory, list[i]); + // if the file is a directory + if (!target.isDirectory()) + continue; + File delete = new File(target, ".delete"); //$NON-NLS-1$ + // and the directory is marked for delete + if (delete.exists()) { + // if rm fails to delete the directory and .delete was removed + if (!AdaptorUtil.rm(target) && !delete.exists()) { + try { + // recreate .delete + FileOutputStream out = new FileOutputStream(delete); + out.close(); + } catch (IOException e) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("Unable to write " + delete.getPath() + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } else { + compact(target); /* descend into directory */ + } + } + } + + public long getFreeSpace() throws IOException { + // cannot implement this without native code! + return -1; + } + + public File getDataFile(BaseData data, String path) { + BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY); + if (storageHook == null) + return null; + return storageHook.getDataFile(path); + } + + public void installNativeCode(BaseData data, String[] nativepaths) throws BundleException { + for (int i = 0; i < nativepaths.length; i++) { + // extract the native code + File nativeFile = data.getBundleFile().getFile(nativepaths[i], true); + if (nativeFile == null) + throw new BundleException(NLS.bind(AdaptorMsg.BUNDLE_NATIVECODE_EXCEPTION, nativepaths[i])); + } + if (nativepaths.length > 0) { + BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY); + if (storageHook != null) + storageHook.setNativePaths(nativepaths); + } + } + + public Dictionary loadManifest(BaseData data) throws BundleException { + return loadManifest(data, false); + } + + public Dictionary loadManifest(BaseData bundleData, boolean firstTime) throws BundleException { + Dictionary result = null; + StorageHook[] dataStorageHooks = bundleData.getStorageHooks(); + for (int i = 0; i < dataStorageHooks.length && result == null; i++) + result = dataStorageHooks[i].getManifest(firstTime); + if (result == null) + result = AdaptorUtil.loadManifestFrom(bundleData); + if (result == null) + throw new BundleException(NLS.bind(AdaptorMsg.MANIFEST_NOT_FOUND_EXCEPTION, Constants.OSGI_BUNDLE_MANIFEST, bundleData.getLocation())); + return result; + } + + public File getExtractFile(BaseData data, String path) { + BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY); + if (storageHook == null) + return null; + // first check the child generation dir + File childGenDir = storageHook.getGenerationDir(); + if (childGenDir != null) { + File childPath = new File(childGenDir, path); + if (childPath.exists()) + return childPath; + } + // now check the parent + File parentGenDir = storageHook.getParentGenerationDir(); + if (parentGenDir != null) { + // there is a parent generation check if the file exists + File parentPath = new File(parentGenDir, path); + if (parentPath.exists()) + // only use the parent generation file if it exists; do not extract there + return parentPath; + } + // did not exist in both locations; create a file for extraction. + File bundleGenerationDir = storageHook.createGenerationDir(); + /* if the generation dir exists, then we have place to cache */ + if (bundleGenerationDir != null && bundleGenerationDir.exists()) + return new File(bundleGenerationDir, path); + return null; + } + + public BaseData[] getInstalledBundles() { + return readBundleDatas(); + } + + private BaseData[] readBundleDatas() { + InputStream bundleDataStream = findStorageStream(LocationManager.BUNDLE_DATA_FILE); + if (bundleDataStream == null) + return null; + try { + DataInputStream in = new DataInputStream(new BufferedInputStream(bundleDataStream)); + try { + byte version = in.readByte(); + if (version != BUNDLEDATA_VERSION) + return null; + timeStamp = in.readLong(); + initialBundleStartLevel = in.readInt(); + nextId = in.readLong(); + + int numStorageHooks = in.readInt(); + StorageHook[] storageHooks = adaptor.getHookRegistry().getStorageHooks(); + if (numStorageHooks != storageHooks.length) + return null; // must have the same number of storagehooks to properly read the data + for (int i = 0; i < numStorageHooks; i++) { + Object storageKey = storageHooks[i].getKey(); + int storageVersion = storageHooks[i].getStorageVersion(); + if (!storageKey.equals(in.readUTF()) || storageVersion != in.readInt()) + return null; // some storage hooks have changed must throw the data away. + } + + int bundleCount = in.readInt(); + ArrayList result = new ArrayList(bundleCount); + long id = -1; + boolean bundleDiscarded = false; + for (int i = 0; i < bundleCount; i++) { + boolean error = false; + BaseData data = null; + try { + id = in.readLong(); + if (id != 0) { + data = loadBaseData(id, in); + data.getBundleFile(); + StorageHook[] dataStorageHooks = data.getStorageHooks(); + for (int j = 0; j < dataStorageHooks.length; j++) + dataStorageHooks[j].validate(); + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("BundleData created: " + data); //$NON-NLS-1$ + processExtension(data, EXTENSION_INITIALIZE); + result.add(data); + } + } catch (IllegalArgumentException e) { + // may be from data.getBundleFile() + bundleDiscarded = true; + error = true; + } catch (BundleException e) { + // should never happen + bundleDiscarded = true; + error = true; + } catch (IOException e) { + bundleDiscarded = true; + error = true; + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + Debug.println("Error reading framework metadata: " + e.getMessage()); //$NON-NLS-1$ + Debug.printStackTrace(e); + } + } + if (error && data != null) { + BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY); + storageHook.delete(true, BaseStorageHook.DEL_BUNDLE_STORE); + } + } + if (bundleDiscarded) + FrameworkProperties.setProperty(EclipseStarter.PROP_REFRESH_BUNDLES, "true"); //$NON-NLS-1$ + return (BaseData[]) result.toArray(new BaseData[result.size()]); + } finally { + in.close(); + } + } catch (IOException e) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + Debug.println("Error reading framework metadata: " + e.getMessage()); //$NON-NLS-1$ + Debug.printStackTrace(e); + } + } + return null; + } + + private void saveAllData(boolean shutdown) { + saveBundleDatas(); + saveStateData(shutdown); + savePermissionStorage(); + if (shutdown) + stateManager.stopDataManager(); + } + + private BasePermissionStorage readPermissionData() { + BasePermissionStorage result = new BasePermissionStorage(this); + InputStream permDataStream = findStorageStream(PERM_DATA_FILE); + if (permDataStream == null) + return result; + try { + DataInputStream in = new DataInputStream(new BufferedInputStream(permDataStream)); + try { + if (PERMDATA_VERSION != in.readByte()) + return result; + // read the default permissions first + int numPerms = in.readInt(); + if (numPerms > 0) { + String[] perms = new String[numPerms]; + for (int i = 0; i < numPerms; i++) + perms[i] = in.readUTF(); + result.setPermissionData(null, perms); + } + int numLocs = in.readInt(); + if (numLocs > 0) + for (int i = 0; i < numLocs; i++) { + String loc = in.readUTF(); + numPerms = in.readInt(); + String[] perms = new String[numPerms]; + for (int j = 0; j < numPerms; j++) + perms[j] = in.readUTF(); + result.setPermissionData(loc, perms); + } + int numCondPerms = in.readInt(); + if (numCondPerms > 0) { + String[] condPerms = new String[numCondPerms]; + for (int i = 0; i < numCondPerms; i++) + condPerms[i] = in.readUTF(); + result.saveConditionalPermissionInfos(condPerms); + } + result.setDirty(false); + } finally { + in.close(); + } + } catch (IOException e) { + adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e)); + } + return result; + } + + private void savePermissionStorage() { + if (permissionStorage == null || !permissionStorage.isDirty()) + return; + try { + ManagedOutputStream fmos = storageManager.getOutputStream(PERM_DATA_FILE); + DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fmos)); + boolean error = true; + try { + out.writeByte(PERMDATA_VERSION); + // always write the default permissions first + String[] defaultPerms = permissionStorage.getPermissionData(null); + out.writeInt(defaultPerms == null ? 0 : defaultPerms.length); + if (defaultPerms != null) + for (int i = 0; i < defaultPerms.length; i++) + out.writeUTF(defaultPerms[i]); + String[] locations = permissionStorage.getLocations(); + out.writeInt(locations == null ? 0 : locations.length); + if (locations != null) + for (int i = 0; i < locations.length; i++) { + out.writeUTF(locations[i]); + String[] perms = permissionStorage.getPermissionData(locations[i]); + out.writeInt(perms == null ? 0 : perms.length); + if (perms != null) + for (int j = 0; j < perms.length; j++) + out.writeUTF(perms[j]); + } + String[] condPerms = permissionStorage.getConditionalPermissionInfos(); + out.writeInt(condPerms == null ? 0 : condPerms.length); + if (condPerms != null) + for (int i = 0; i < condPerms.length; i++) + out.writeUTF(condPerms[i]); + out.close(); + permissionStorage.setDirty(false); + error = false; + } finally { + // if something happens, don't close a corrupt file + if (error) { + fmos.abort(); + try { + out.close(); + } catch (IOException e) {/*ignore*/ + } + } + } + } catch (IOException e) { + adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e)); + return; + } + } + + private void saveBundleDatas() { + // the cache and the state match + if (stateManager == null || isReadOnly() || timeStamp == stateManager.getSystemState().getTimeStamp()) + return; + try { + ManagedOutputStream fmos = storageManager.getOutputStream(LocationManager.BUNDLE_DATA_FILE); + DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fmos)); + boolean error = true; + try { + out.writeByte(BUNDLEDATA_VERSION); + out.writeLong(stateManager.getSystemState().getTimeStamp()); + out.writeInt(initialBundleStartLevel); + out.writeLong(nextId); + + StorageHook[] storageHooks = adaptor.getHookRegistry().getStorageHooks(); + out.writeInt(storageHooks.length); + for (int i = 0; i < storageHooks.length; i++) { + out.writeUTF((String) storageHooks[i].getKey()); + out.writeInt(storageHooks[i].getStorageVersion()); + } + + Bundle[] bundles = context.getBundles(); + out.writeInt(bundles.length); + for (int i = 0; i < bundles.length; i++) { + long id = bundles[i].getBundleId(); + out.writeLong(id); + if (id != 0) { + BundleData data = ((org.eclipse.osgi.framework.internal.core.AbstractBundle) bundles[i]).getBundleData(); + saveBaseData((BaseData) data, out); + } + } + out.close(); + // update the 'timeStamp' after the changed Meta data is saved. + timeStamp = stateManager.getSystemState().getTimeStamp(); + error = false; + } finally { + // if something happens, don't close a corrupt file + if (error) { + fmos.abort(); + try { + out.close(); + } catch (IOException e) {/*ignore*/ + } + } + } + } catch (IOException e) { + adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e)); + return; + } + } + + private void saveStateData(boolean shutdown) { + if (stateManager == null || isReadOnly() || !stateManager.saveNeeded()) + return; + try { + File stateTmpFile = File.createTempFile(LocationManager.STATE_FILE, ".new", LocationManager.getOSGiConfigurationDir()); //$NON-NLS-1$ + File lazyTmpFile = File.createTempFile(LocationManager.LAZY_FILE, ".new", LocationManager.getOSGiConfigurationDir()); //$NON-NLS-1$ + if (shutdown) + stateManager.shutdown(stateTmpFile, lazyTmpFile); + else + synchronized (stateManager) { + stateManager.update(stateTmpFile, lazyTmpFile); + } + storageManager.lookup(LocationManager.STATE_FILE, true); + storageManager.lookup(LocationManager.LAZY_FILE, true); + storageManager.update(new String[] {LocationManager.STATE_FILE, LocationManager.LAZY_FILE}, new String[] {stateTmpFile.getName(), lazyTmpFile.getName()}); + } catch (IOException e) { + adaptor.getFrameworkLog().log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e)); + } + } + + public PermissionStorage getPermissionStorage() throws IOException { + if (permissionStorage == null) + permissionStorage = readPermissionData(); + return permissionStorage; + } + + public int getInitialBundleStartLevel() { + return initialBundleStartLevel; + } + + public void setInitialBundleStartLevel(int value) { + this.initialBundleStartLevel = value; + requestSave(); + } + + public void save(BaseData data) throws IOException { + if (data.isDirty()) { + timeStamp--; // Change the value of the timeStamp, as a marker that something changed. + requestSave(); + data.setDirty(false); + } + } + + public BundleOperation installBundle(String location, URLConnection source) { + BaseData data = createBaseData(getNextBundleId(), location); + return new BundleInstall(data, source, this); + } + + public BundleOperation updateBundle(BaseData data, URLConnection source) { + return new BundleUpdate(data, source, this); + } + + public BundleOperation uninstallBundle(BaseData data) { + return new BundleUninstall(data, this); + } + + protected Object getBundleContent(BaseData bundledata) throws IOException { + BaseStorageHook storageHook = (BaseStorageHook) bundledata.getStorageHook(BaseStorageHook.KEY); + if (storageHook == null) + throw new IllegalStateException(); + return storageHook.isReference() ? new File(storageHook.getFileName()) : new File(storageHook.getGenerationDir(), storageHook.getFileName()); + } + + public BundleFile createBundleFile(Object content, BaseData data) throws IOException { + boolean base = false; + if (content == null) { + // this must be a request for the base bundlefile + base = true; + // get the content of this bundle + content = getBundleContent(data); + } + // Ask factories before doing the default behavior + BundleFileFactoryHook[] factories = adaptor.getHookRegistry().getBundleFileFactoryHooks(); + for (int i = 0; i < factories.length; i++) { + BundleFile result = factories[i].createBundleFile(content, data, base); + if (result != null) + return result; + } + // No factories configured or they declined to create the bundle file; do default + if (content instanceof File) { + File file = (File) content; + if (file.isDirectory()) + return new DirBundleFile(file); + return new ZipBundleFile(file, data); + } + // nothing we can do; must throw exception for the content + throw new IOException("Cannot create bundle file for content of type: " + content.getClass().getName()); + } + + public synchronized StateManager getStateManager() { + if (stateManager != null) + return stateManager; + stateManager = readStateData(); + checkSystemState(stateManager.getSystemState()); + return stateManager; + } + + private void checkSystemState(State state) { + BundleDescription[] bundles = state.getBundles(); + if (bundles == null) + return; + boolean removedBundle = false; + for (int i = 0; i < bundles.length; i++) { + if (context.getBundle(bundles[i].getBundleId()) == null) { + state.removeBundle(bundles[i]); + removedBundle = true; + } + } + if (removedBundle) + state.resolve(false); // do a full resolve + BundleDescription systemBundle = state.getBundle(0); + if (systemBundle == null || !systemBundle.isResolved()) + // this would be a bug in the framework + throw new IllegalStateException(); + } + + private StateManager readStateData() { + File[] stateFiles = findStorageFiles(new String[] {LocationManager.STATE_FILE, LocationManager.LAZY_FILE}); + File stateFile = stateFiles[0]; + File lazyFile = stateFiles[1]; + + stateManager = new StateManager(stateFile, lazyFile, context, timeStamp); + State systemState = null; + if (!invalidState) { + systemState = stateManager.readSystemState(); + if (systemState != null) + return stateManager; + } + systemState = stateManager.createSystemState(); + Bundle[] installedBundles = context.getBundles(); + if (installedBundles == null) + return stateManager; + StateObjectFactory factory = stateManager.getFactory(); + for (int i = 0; i < installedBundles.length; i++) { + AbstractBundle toAdd = (AbstractBundle) installedBundles[i]; + try { + // make sure we get the real manifest as if this is the first time. + Dictionary toAddManifest = loadManifest((BaseData) toAdd.getBundleData(), true); + BundleDescription newDescription = factory.createBundleDescription(systemState, toAddManifest, toAdd.getLocation(), toAdd.getBundleId()); + systemState.addBundle(newDescription); + } catch (BundleException be) { + // just ignore bundle datas with invalid manifests + } + } + // we need the state resolved + systemState.setTimeStamp(timeStamp); + systemState.resolve(); + invalidState = false; + return stateManager; + } + + private File[] findStorageFiles(String[] fileNames) { + File[] storageFiles = new File[fileNames.length]; + try { + for (int i = 0; i < storageFiles.length; i++) + storageFiles[i] = storageManager.lookup(fileNames[i], false); + } catch (IOException ex) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + Debug.println("Error reading state file " + ex.getMessage()); //$NON-NLS-1$ + Debug.printStackTrace(ex); + } + } + boolean success = true; + for (int i = 0; i < storageFiles.length; i++) + if (storageFiles[i] == null || !storageFiles[i].isFile()) { + success = false; + break; + } + if (success) + return storageFiles; + //if it does not exist, try to read it from the parent + Location parentConfiguration = null; + Location currentConfiguration = LocationManager.getConfigurationLocation(); + if (currentConfiguration != null && (parentConfiguration = currentConfiguration.getParentLocation()) != null) { + try { + File stateLocationDir = new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME); + StorageManager newFileManager = initFileManager(stateLocationDir, "none", true); //$NON-NLS-1$); + for (int i = 0; i < storageFiles.length; i++) + storageFiles[i] = newFileManager.lookup(fileNames[i], false); + newFileManager.close(); + } catch (IOException ex) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + Debug.println("Error reading state file " + ex.getMessage()); //$NON-NLS-1$ + Debug.printStackTrace(ex); + } + } + } else { + try { + //it did not exist in either place, so create it in the original location + if (!isReadOnly()) { + for (int i = 0; i < storageFiles.length; i++) + storageFiles[i] = storageManager.lookup(fileNames[i], true); + } + } catch (IOException ex) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + Debug.println("Error reading state file " + ex.getMessage()); //$NON-NLS-1$ + Debug.printStackTrace(ex); + } + } + } + return storageFiles; + } + + public void frameworkStart(BundleContext fwContext) throws BundleException { + this.context = fwContext; + // System property can be set to enable state saver or not. + if (Boolean.valueOf(FrameworkProperties.getProperty(BaseStorage.PROP_ENABLE_STATE_SAVER, "true")).booleanValue()) //$NON-NLS-1$ + stateSaver = new StateSaver(); + + } + + public void frameworkStop(BundleContext fwContext) throws BundleException { + if (stateSaver != null) + stateSaver.shutdown(); + saveAllData(true); + storageManager.close(); + } + + public void frameworkStopping(BundleContext fwContext) { + // do nothing in storage + } + + public void addProperties(Properties properties) { + // set the extension support if we found the addURL method + if (addURLMethod != null) + properties.put(Constants.SUPPORTS_FRAMEWORK_EXTENSION, "true"); //$NON-NLS-1$ + // store bundleStore back into adaptor properties for others to see + properties.put(BaseStorage.PROP_BUNDLE_STORE, getBundleStoreRoot().getAbsolutePath()); + } + + private InputStream findStorageStream(String fileName) { + InputStream storageStream = null; + try { + storageStream = storageManager.getInputStream(fileName); + } catch (IOException ex) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + Debug.println("Error reading framework metadata: " + ex.getMessage()); //$NON-NLS-1$ + Debug.printStackTrace(ex); + } + } + if (storageStream == null) { + Location currentConfiguration = LocationManager.getConfigurationLocation(); + Location parentConfiguration = null; + if (currentConfiguration != null && (parentConfiguration = currentConfiguration.getParentLocation()) != null) { + try { + File bundledataLocationDir = new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME); + StorageManager newStorageManager = initFileManager(bundledataLocationDir, "none", true); //$NON-NLS-1$ + storageStream = newStorageManager.getInputStream(fileName); + newStorageManager.close(); + } catch (MalformedURLException e1) { + // This will not happen since all the URLs are derived by us + // and we are GODS! + } catch (IOException e1) { + // That's ok we will regenerate the .bundleData + } + } + } + return storageStream; + } + + protected void saveBaseData(BaseData bundledata, DataOutputStream out) throws IOException { + StorageHook[] hooks = bundledata.getStorageHooks(); + out.writeInt(hooks.length); + for (int i = 0; i < hooks.length; i++) { + out.writeUTF((String) hooks[i].getKey()); + hooks[i].save(out); + } + } + + protected BaseData loadBaseData(long id, DataInputStream in) throws IOException { + BaseData result = new BaseData(id, adaptor); + int numHooks = in.readInt(); + StorageHook[] hooks = new StorageHook[numHooks]; + for (int i = 0; i < numHooks; i++) { + String hookKey = in.readUTF(); + StorageHook storageHook = (StorageHook) storageHooks.getByKey(hookKey); + if (storageHook == null) + throw new IOException(); + hooks[i] = storageHook.load(result, in); + } + result.setStorageHooks(hooks); + return result; + } + + protected BaseData createBaseData(long id, String location) { + BaseData result = new BaseData(id, adaptor); + result.setLocation(location); + return result; + } + + public String getInstallPath() { + return installPath; + } + + private void cleanOSGiCache() { + File osgiConfig = LocationManager.getOSGiConfigurationDir(); + if (!AdaptorUtil.rm(osgiConfig)) { + // TODO log error? + } + } + + /** + * Processes an extension bundle + * @param bundleData the extension bundle data + * @param type the type of extension bundle + * @throws BundleException on any errors or if the extension bundle type is not supported + */ + protected void processExtension(BaseData bundleData, byte type) throws BundleException { + if ((bundleData.getType() & BundleData.TYPE_FRAMEWORK_EXTENSION) != 0) { + validateExtension(bundleData); + processFrameworkExtension(bundleData, type); + } else if ((bundleData.getType() & BundleData.TYPE_BOOTCLASSPATH_EXTENSION) != 0) { + validateExtension(bundleData); + processBootExtension(bundleData, type); + } + } + + /** + * Validates the extension bundle metadata + * @param bundleData the extension bundle data + * @throws BundleException if the extension bundle metadata is invalid + */ + private void validateExtension(BundleData bundleData) throws BundleException { + Dictionary extensionManifest = bundleData.getManifest(); + if (extensionManifest.get(Constants.IMPORT_PACKAGE) != null) + throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_EXTENSION_IMPORT_ERROR, bundleData.getLocation())); + if (extensionManifest.get(Constants.REQUIRE_BUNDLE) != null) + throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_EXTENSION_REQUIRE_ERROR, bundleData.getLocation())); + if (extensionManifest.get(Constants.BUNDLE_NATIVECODE) != null) + throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_EXTENSION_NATIVECODE_ERROR, bundleData.getLocation())); + } + + /** + * Processes a framework extension bundle + * @param bundleData the extension bundle data + * @param type the type of extension bundle + * @throws BundleException on errors or if framework extensions are not supported + */ + protected void processFrameworkExtension(BaseData bundleData, byte type) throws BundleException { + if (addURLMethod == null) + throw new BundleException("Framework extensions are not supported.", new UnsupportedOperationException()); //$NON-NLS-1$ + if ((type & (EXTENSION_UNINSTALLED | EXTENSION_UPDATED)) != 0) + // if uninstalled or updated then do nothing framework must be restarted. + return; + + // first make sure this BundleData is not on the pre-configured osgi.framework.extensions list + String[] extensions = getConfiguredExtensions(); + for (int i = 0; i < extensions.length; i++) + if (extensions[i].equals(bundleData.getSymbolicName())) + return; + File[] files = getExtensionFiles(bundleData); + if (files == null) + return; + ClassLoader cl = getClass().getClassLoader(); + for (int i = 0; i < files.length; i++) { + if (files[i] == null) + continue; + Throwable exceptionLog = null; + try { + addURLMethod.invoke(cl, new Object[] {files[i].toURL()}); + } catch (InvocationTargetException e) { + exceptionLog = e.getTargetException(); + } catch (Throwable t) { + exceptionLog = t; + } finally { + if (exceptionLog != null) + adaptor.getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundleData.getBundle(), exceptionLog); + } + } + try { + cl.loadClass("thisIsNotAClass"); // initialize the new urls //$NON-NLS-1$ + } catch (ClassNotFoundException e) { + // do nothing + } + } + + /** + * Returns a list of configured extensions + * @return a list of configured extensions + */ + protected String[] getConfiguredExtensions() { + if (configuredExtensions != null) + return configuredExtensions; + String prop = FrameworkProperties.getProperty(BaseStorage.PROP_FRAMEWORK_EXTENSIONS); + if (prop == null || prop.trim().length() == 0) + configuredExtensions = new String[0]; + else + configuredExtensions = ManifestElement.getArrayFromList(prop); + return configuredExtensions; + } + + /** + * Processes a boot extension bundle + * @param bundleData the extension bundle data + * @param type the type of extension bundle + * @throws BundleException on errors or if boot extensions are not supported + */ + protected void processBootExtension(BundleData bundleData, byte type) throws BundleException { + throw new BundleException("Boot classpath extensions are not supported.", new UnsupportedOperationException()); //$NON-NLS-1$ + } + + private void initBundleStoreRoot() { + File configurationLocation = LocationManager.getOSGiConfigurationDir(); + if (configurationLocation != null) + bundleStoreRoot = new File(configurationLocation, LocationManager.BUNDLES_DIR); + else + // last resort just default to "bundles" + bundleStoreRoot = new File(LocationManager.BUNDLES_DIR); + } + + public File getBundleStoreRoot() { + if (bundleStoreRoot == null) + initBundleStoreRoot(); + return bundleStoreRoot; + } + + /** + * Returns a list of classpath files for an extension bundle + * @param bundleData the bundle data for an extension bundle + * @return a list of classpath files for an extension bundle + */ + protected File[] getExtensionFiles(BaseData bundleData) { + File[] files = null; + try { + String[] paths = bundleData.getClassPath(); + // TODO need to be smarter about dev path here + if (FrameworkProperties.getProperty("osgi.dev") != null) { //$NON-NLS-1$ + String[] origPaths = paths; + paths = new String[origPaths.length + 1]; + System.arraycopy(origPaths, 0, paths, 0, origPaths.length); + paths[paths.length - 1] = "bin"; //$NON-NLS-1$ + } + ArrayList results = new ArrayList(paths.length); + for (int i = 0; i < paths.length; i++) { + if (".".equals(paths[i])) //$NON-NLS-1$ + results.add(bundleData.getBundleFile().getBaseFile()); + else { + File result = bundleData.getBundleFile().getFile(paths[i], false); + if (result != null) + results.add(result); + } + } + return (File[]) results.toArray(new File[results.size()]); + } catch (BundleException e) { + adaptor.getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundleData.getBundle(), e); + } + return files; + } + + void requestSave() { + // Only when the State saver is enabled will the stateSaver be started. + if (stateSaver == null) + return; + stateSaver.requestSave(); + } + + /** + * Updates the state mananager with an updated/installed/uninstalled bundle + * @param bundleData the modified bundle + * @param type the type of modification + * @throws BundleException + */ + public void updateState(BundleData bundleData, int type) throws BundleException { + if (stateManager == null) { + invalidState = true; + return; + } + State systemState = stateManager.getSystemState(); + switch (type) { + case BundleEvent.UPDATED : + systemState.removeBundle(bundleData.getBundleID()); + // fall through to INSTALLED + case BundleEvent.INSTALLED : + BundleDescription newDescription = stateManager.getFactory().createBundleDescription(systemState, bundleData.getManifest(), bundleData.getLocation(), bundleData.getBundleID()); + systemState.addBundle(newDescription); + break; + case BundleEvent.UNINSTALLED : + systemState.removeBundle(bundleData.getBundleID()); + break; + } + } + + private static Method findaddURLMethod(Class clazz) { + if (clazz == null) + return null; // ends the recursion when getSuperClass returns null + try { + Method result = clazz.getDeclaredMethod("addURL", new Class[] {URL.class}); //$NON-NLS-1$ + result.setAccessible(true); + return result; + } catch (NoSuchMethodException e) { + // do nothing look in super class below + } catch (SecurityException e) { + // if we do not have the permissions then we will not find the method + } + return findaddURLMethod(clazz.getSuperclass()); + } + + private class StateSaver implements Runnable { + private long delay_interval = 30000; // 30 seconds. + private long max_total_delay_interval = 1800000; // 30 minutes. + private boolean shutdown = false; + private long lastSaveTime = 0; + private Thread runningThread = null; + + StateSaver() { + String prop = FrameworkProperties.getProperty("eclipse.stateSaveDelayInterval"); //$NON-NLS-1$ + if (prop != null) { + try { + long val = Long.parseLong(prop); + if (val >= 1000 && val <= 1800000) { + delay_interval = val; + max_total_delay_interval = val * 60; + } + } catch (NumberFormatException e) { + // ignore + } + } + } + + public void run() { + State systemState = adaptor.getState(); + synchronized (systemState) { + long firstSaveTime = lastSaveTime; + long curSaveTime = 0; + long delayTime; + do { + do { + if ((System.currentTimeMillis() - firstSaveTime) > max_total_delay_interval) + // Waiting time has been too long, so break to start saving State data to file. + break; + delayTime = Math.min(delay_interval, lastSaveTime - curSaveTime); + curSaveTime = lastSaveTime; + // wait for other save requests + try { + if (!shutdown) + systemState.wait(delayTime); + } catch (InterruptedException ie) { + // force break from do/while loops + curSaveTime = lastSaveTime; + break; + } + + // Continue the loop if 'lastSaveTime' is increased again during waiting. + } while (!shutdown && curSaveTime < lastSaveTime); + // Save State and Meta data. + saveAllData(false); + // Continue the loop if Saver is asked again during saving State data to file. + } while (!shutdown && curSaveTime < lastSaveTime); + runningThread = null; // clear runningThread + } + } + + void shutdown() { + State systemState = adaptor.getState(); + Thread joinWith = null; + synchronized (systemState) { + shutdown = true; + joinWith = runningThread; + systemState.notifyAll(); // To wakeup sleeping thread. + } + try { + if (joinWith != null) + // There should be no deadlock when 'shutdown' is true. + joinWith.join(); + } catch (InterruptedException ie) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) { + Debug.println("Error shutdowning StateSaver: " + ie.getMessage()); //$NON-NLS-1$ + Debug.printStackTrace(ie); + } + } + } + + void requestSave() { + State systemState = adaptor.getState(); + synchronized (systemState) { + lastSaveTime = System.currentTimeMillis(); + if (runningThread == null) { + runningThread = new Thread(this, "State Saver"); //$NON-NLS-1$ + runningThread.start(); + } + } + } + } + + public long getNextBundleId() { + return nextId++; + } + + public static BaseStorage getInstance() { + return INSTANCE; + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java new file mode 100644 index 000000000..2504befd2 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BaseStorageHook.java @@ -0,0 +1,302 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.internal.baseadaptor; + +import java.io.*; +import java.util.Dictionary; +import org.eclipse.core.runtime.adaptor.LocationManager; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.hooks.StorageHook; +import org.eclipse.osgi.framework.adaptor.*; +import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.framework.internal.core.*; +import org.eclipse.osgi.framework.util.KeyedElement; +import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.osgi.util.ManifestElement; +import org.osgi.framework.BundleException; +import org.osgi.framework.Version; + +public class BaseStorageHook implements StorageHook { + public static final String KEY = BaseStorageHook.class.getName(); + public static final int HASHCODE = KEY.hashCode(); + public static final int DEL_BUNDLE_STORE = 0x01; + public static final int DEL_GENERATION = 0x02; + private static final int STORAGE_VERSION = 1; + + /** bundle's file name */ + private String fileName; + /** native code paths for this BundleData */ + private String[] nativePaths; + /** bundle generation */ + private int generation = 1; + /** Is bundle a reference */ + private boolean reference; + + private BaseData bundleData; + private BaseStorage storage; + private File bundleStore; + private File dataStore; + + public BaseStorageHook(BaseStorage storage) { + this.storage = storage; + } + + public int getStorageVersion() { + return STORAGE_VERSION; + } + + public StorageHook create(BaseData bundledata) throws BundleException { + BaseStorageHook storageHook = new BaseStorageHook(storage); + storageHook.bundleData = bundledata; + return storageHook; + } + + public void initialize(Dictionary manifest) throws BundleException { + BaseStorageHook.loadManifest(bundleData, manifest); + } + + static void loadManifest(BaseData target, Dictionary manifest) throws BundleException { + try { + target.setVersion(Version.parseVersion((String) manifest.get(Constants.BUNDLE_VERSION))); + } catch (IllegalArgumentException e) { + target.setVersion(new InvalidVersion((String) manifest.get(Constants.BUNDLE_VERSION))); + } + ManifestElement[] bsnHeader = ManifestElement.parseHeader(Constants.BUNDLE_SYMBOLICNAME, (String) manifest.get(Constants.BUNDLE_SYMBOLICNAME)); + int bundleType = 0; + if (bsnHeader != null) { + target.setSymbolicName(bsnHeader[0].getValue()); + String singleton = bsnHeader[0].getDirective(Constants.SINGLETON_DIRECTIVE); + if (singleton == null) + singleton = bsnHeader[0].getAttribute(Constants.SINGLETON_DIRECTIVE); + if ("true".equals(singleton)) //$NON-NLS-1$ + bundleType |= BundleData.TYPE_SINGLETON; + } + target.setClassPathString((String) manifest.get(Constants.BUNDLE_CLASSPATH)); + target.setActivator((String) manifest.get(Constants.BUNDLE_ACTIVATOR)); + String host = (String) manifest.get(Constants.FRAGMENT_HOST); + if (host != null) { + bundleType |= BundleData.TYPE_FRAGMENT; + ManifestElement[] hostElement = ManifestElement.parseHeader(Constants.FRAGMENT_HOST, host); + if (Constants.getInternalSymbolicName().equals(hostElement[0].getValue()) || Constants.OSGI_SYSTEM_BUNDLE.equals(hostElement[0].getValue())) { + String extensionType = hostElement[0].getDirective("extension"); //$NON-NLS-1$ + if (extensionType == null || extensionType.equals("framework")) //$NON-NLS-1$ + bundleType |= BundleData.TYPE_FRAMEWORK_EXTENSION; + else + bundleType |= BundleData.TYPE_BOOTCLASSPATH_EXTENSION; + } + } + target.setType(bundleType); + target.setExecutionEnvironment((String) manifest.get(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)); + target.setDynamicImports((String) manifest.get(Constants.DYNAMICIMPORT_PACKAGE)); + } + + public StorageHook load(BaseData target, DataInputStream in) throws IOException { + target.setLocation(AdaptorUtil.readString(in, false)); + target.setSymbolicName(AdaptorUtil.readString(in, false)); + target.setVersion(AdaptorUtil.loadVersion(in)); + target.setActivator(AdaptorUtil.readString(in, false)); + target.setClassPathString(AdaptorUtil.readString(in, false)); + target.setExecutionEnvironment(AdaptorUtil.readString(in, false)); + target.setDynamicImports(AdaptorUtil.readString(in, false)); + target.setStartLevel(in.readInt()); + target.setStatus(in.readInt()); + target.setType(in.readInt()); + target.setLastModified(in.readLong()); + target.setDirty(false); // make sure to reset the dirty bit; + + BaseStorageHook storageHook = new BaseStorageHook(storage); + storageHook.bundleData = target; + storageHook.generation = in.readInt(); + storageHook.reference = in.readBoolean(); + storageHook.fileName = getAbsolute(storageHook.reference, AdaptorUtil.readString(in, false)); + int nativePathCount = in.readInt(); + storageHook.nativePaths = nativePathCount > 0 ? new String[nativePathCount] : null; + for (int i = 0; i < nativePathCount; i++) + storageHook.nativePaths[i] = in.readUTF(); + return storageHook; + } + + private String getAbsolute(boolean isReference, String path) { + if (!isReference) + return path; + // fileName for bundles installed with reference URLs is stored relative to the install location + File storedPath = new File(path); + if (!storedPath.isAbsolute()) + // make sure it has the absolute location instead + return new FilePath(storage.getInstallPath() + path).toString(); + return path; + } + + public void save(DataOutputStream out) throws IOException { + if (bundleData == null) + throw new IllegalStateException(); + AdaptorUtil.writeStringOrNull(out, bundleData.getLocation()); + AdaptorUtil.writeStringOrNull(out, bundleData.getSymbolicName()); + AdaptorUtil.writeStringOrNull(out, bundleData.getVersion().toString()); + AdaptorUtil.writeStringOrNull(out, bundleData.getActivator()); + AdaptorUtil.writeStringOrNull(out, bundleData.getClassPathString()); + AdaptorUtil.writeStringOrNull(out, bundleData.getExecutionEnvironment()); + AdaptorUtil.writeStringOrNull(out, bundleData.getDynamicImports()); + StorageHook[] hooks = bundleData.getStorageHooks(); + boolean forgetStartLevel = false; + for (int i = 0; i < hooks.length && !forgetStartLevel; i++) + forgetStartLevel = hooks[i].forgetStartLevelChange(bundleData.getStartLevel()); + out.writeInt(!forgetStartLevel ? bundleData.getStartLevel() : 1); + boolean forgetStatus = false; + // see if we should forget the persistently started flag + for (int i = 0; i < hooks.length && !forgetStatus; i++) + forgetStatus = hooks[i].forgetStatusChange(bundleData.getStatus()); + out.writeInt(!forgetStatus ? bundleData.getStatus() : (~Constants.BUNDLE_STARTED) & bundleData.getStatus()); + out.writeInt(bundleData.getType()); + out.writeLong(bundleData.getLastModified()); + + out.writeInt(getGeneration()); + out.writeBoolean(isReference()); + String storedFileName = isReference() ? new FilePath(storage.getInstallPath()).makeRelative(new FilePath(getFileName())) : getFileName(); + AdaptorUtil.writeStringOrNull(out, storedFileName); + if (nativePaths == null) + out.writeInt(0); + else { + out.writeInt(nativePaths.length); + for (int i = 0; i < nativePaths.length; i++) + out.writeUTF(nativePaths[i]); + } + + } + + public int getKeyHashCode() { + return HASHCODE; + } + + public boolean compare(KeyedElement other) { + return other.getKey() == KEY; + } + + public Object getKey() { + return KEY; + } + + public String getFileName() { + return fileName; + } + + public int getGeneration() { + return generation; + } + + public String[] getNativePaths() { + return nativePaths; + } + + public void setNativePaths(String[] nativePaths) { + this.nativePaths = nativePaths; + } + + public boolean isReference() { + return reference; + } + + public File getBundleStore() { + if (bundleStore == null) + bundleStore = new File(storage.getBundleStoreRoot(), String.valueOf(bundleData.getBundleID())); + return bundleStore; + } + + public File getDataFile(String path) { + // lazily initialize dirData to prevent early access to configuration location + if (dataStore == null) + dataStore = new File(getBundleStore(), BaseStorage.DATA_DIR_NAME); + if (path != null && !dataStore.exists() && (storage.isReadOnly() || !dataStore.mkdirs())) + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("Unable to create bundle data directory: " + dataStore.getPath()); //$NON-NLS-1$ + return path == null ? dataStore : new File(dataStore, path); + } + + void delete(boolean postpone, int type) throws IOException { + File delete = null; + switch (type) { + case DEL_GENERATION : + delete = getGenerationDir(); + break; + case DEL_BUNDLE_STORE : + delete = getBundleStore(); + break; + } + if (delete != null && delete.exists() && (postpone || !AdaptorUtil.rm(delete))) { + /* create .delete */ + FileOutputStream out = new FileOutputStream(new File(delete, ".delete")); //$NON-NLS-1$ + out.close(); + } + } + + File getGenerationDir() { + return new File(getBundleStore(), String.valueOf(getGeneration())); + } + + File getParentGenerationDir() { + Location parentConfiguration = null; + Location currentConfiguration = LocationManager.getConfigurationLocation(); + if (currentConfiguration != null && (parentConfiguration = currentConfiguration.getParentLocation()) != null) + return new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + '/' + LocationManager.BUNDLES_DIR + '/' + bundleData.getBundleID() + '/' + getGeneration()); + return null; + } + + File createGenerationDir() { + File generationDir = getGenerationDir(); + if (!generationDir.exists() && (storage.isReadOnly() || !generationDir.mkdirs())) + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("Unable to create bundle generation directory: " + generationDir.getPath()); //$NON-NLS-1$ + return generationDir; + } + + public void setReference(boolean reference) { + this.reference = reference; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public void copy(StorageHook storageHook) { + if (!(storageHook instanceof BaseStorageHook)) + throw new IllegalArgumentException(); + BaseStorageHook hook = (BaseStorageHook) storageHook; + bundleStore = hook.bundleStore; + dataStore = hook.dataStore; + generation = hook.generation + 1; + // fileName and reference will be set by update + } + + public void validate() throws IllegalArgumentException { + // do nothing + } + + public Dictionary getManifest(boolean firstLoad) throws BundleException { + // do nothing + return null; + } + + public boolean forgetStatusChange(int status) { + // do nothing + return false; + } + + public boolean forgetStartLevelChange(int startlevel) { + // do nothing + return false; + } + + public boolean matchDNChain(String pattern) { + // do nothing + return false; + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BundleInstall.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BundleInstall.java new file mode 100644 index 000000000..6b52f01cf --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BundleInstall.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.internal.baseadaptor; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.Dictionary; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.hooks.StorageHook; +import org.eclipse.osgi.framework.adaptor.BundleData; +import org.eclipse.osgi.framework.adaptor.BundleOperation; +import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.framework.internal.core.ReferenceInputStream; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.*; + +public class BundleInstall implements BundleOperation { + private BaseData data; + private URLConnection source; + private BaseStorage storage; + + public BundleInstall(BaseData data, URLConnection source, BaseStorage storage) { + this.data = data; + this.source = source; + this.storage = storage; + } + + /** + * Begin the operation on the bundle (install, update, uninstall). + * + * @return BundleData object for the target bundle. + * @throws BundleException If a failure occured modifiying peristent storage. + */ + public BundleData begin() throws BundleException { + try { + InputStream in = null; + try { + data.setLastModified(System.currentTimeMillis()); + data.setStartLevel(storage.getInitialBundleStartLevel()); + StorageHook[] storageHooks = data.getAdaptor().getHookRegistry().getStorageHooks(); + StorageHook[] instanceHooks = new StorageHook[storageHooks.length]; + for (int i = 0; i < storageHooks.length; i++) + instanceHooks[i] = storageHooks[i].create(data); + data.setStorageHooks(instanceHooks); + BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY); + in = source.getInputStream(); + URL sourceURL = source.getURL(); + String protocol = sourceURL == null ? null : sourceURL.getProtocol(); + if (in instanceof ReferenceInputStream) { + URL reference = ((ReferenceInputStream) in).getReference(); + if (!"file".equals(reference.getProtocol())) //$NON-NLS-1$ + throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, reference)); + storageHook.setReference(true); + storageHook.setFileName(reference.getPath()); + } else { + File genDir = storageHook.createGenerationDir(); + if (!genDir.exists()) + throw new IOException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, genDir.getPath())); + storageHook.setReference(false); + storageHook.setFileName(BaseStorage.BUNDLEFILE_NAME); + File outFile = new File(genDir, storageHook.getFileName()); + if ("file".equals(protocol)) { //$NON-NLS-1$ + File inFile = new File(source.getURL().getPath()); + if (inFile.isDirectory()) + AdaptorUtil.copyDir(inFile, outFile); + else + AdaptorUtil.readFile(in, outFile); + } else { + AdaptorUtil.readFile(in, outFile); + } + } + Dictionary manifest = storage.loadManifest(data, true); + for (int i = 0; i < instanceHooks.length; i++) + instanceHooks[i].initialize(manifest); + } finally { + try { + if (in != null) + in.close(); + } catch (IOException e) { + // do nothing + } + } + } catch (IOException ioe) { + throw new BundleException(AdaptorMsg.BUNDLE_READ_EXCEPTION, ioe); + } + + return (data); + } + + public void undo() { + if (data != null) { + try { + data.close(); + } catch (IOException e) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + Debug.println("Unable to close " + data + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + if (data != null) { + BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY); + try { + if (storageHook != null) + storageHook.delete(false, BaseStorageHook.DEL_BUNDLE_STORE); + } catch (IOException e) { + data.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, data.getBundle(), e); + } + } + } + + public void commit(boolean postpone) throws BundleException { + storage.processExtension(data, BaseStorage.EXTENSION_INSTALLED); + try { + data.save(); + } catch (IOException e) { + throw new BundleException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION, e); + } + storage.updateState(data, BundleEvent.INSTALLED); + } + +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BundleUninstall.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BundleUninstall.java new file mode 100644 index 000000000..05d1fda15 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BundleUninstall.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.internal.baseadaptor; + +import java.io.*; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.framework.adaptor.BundleData; +import org.eclipse.osgi.framework.adaptor.BundleOperation; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleException; + +public class BundleUninstall implements BundleOperation { + private BaseData data; + private BaseStorage storage; + + public BundleUninstall(BaseData data, BaseStorage storage) { + this.data = data; + this.storage = storage; + } + + /** + * Perform the change to persistent storage. + * + * @return Bundle object for the target bundle. + * @throws BundleException If a failure occured modifiying peristent storage. + */ + public BundleData begin() throws BundleException { + return data; + } + + /** + * Commit the change to persistent storage. + * + * @param postpone If true, the bundle's persistent + * storage cannot be immediately reclaimed. + * @throws BundleException If a failure occured modifiying peristent storage. + */ + public void commit(boolean postpone) throws BundleException { + BaseStorageHook storageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY); + try { + storageHook.delete(postpone, BaseStorageHook.DEL_BUNDLE_STORE); + } catch (IOException e) { + // nothing we can do + } + storage.processExtension(data, BaseStorage.EXTENSION_UNINSTALLED); + data.setLastModified(System.currentTimeMillis()); + storage.updateState(data, BundleEvent.UNINSTALLED); + } + + /** + * Undo the change to persistent storage. + * + * @throws BundleException If a failure occured modifiying peristent storage. + */ + public void undo() throws BundleException { + // do nothing + } + +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BundleUpdate.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BundleUpdate.java new file mode 100644 index 000000000..d605bbed7 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/BundleUpdate.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.internal.baseadaptor; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.Dictionary; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.hooks.StorageHook; +import org.eclipse.osgi.framework.adaptor.BundleData; +import org.eclipse.osgi.framework.adaptor.BundleOperation; +import org.eclipse.osgi.framework.internal.core.ReferenceInputStream; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.*; + +public class BundleUpdate implements BundleOperation { + private BaseData data; + private BaseData newData; + private URLConnection source; + private BaseStorage storage; + + public BundleUpdate(BaseData data, URLConnection source, BaseStorage storage) { + this.data = data; + this.source = source; + this.storage = storage; + } + + /** + * Perform the change to persistent storage. + * + * @return Bundle object for the target bundle. + * @throws BundleException if an error occurs + */ + public BundleData begin() throws BundleException { + try { + newData = storage.createBaseData(data.getBundleID(), data.getLocation()); + newData.setLastModified(System.currentTimeMillis()); + newData.setStartLevel(data.getStartLevel()); + newData.setStatus(data.getStatus()); + // load the storage hooks into the new data + StorageHook[] storageHooks = data.getAdaptor().getHookRegistry().getStorageHooks(); + StorageHook[] instanceHooks = new StorageHook[storageHooks.length]; + for (int i = 0; i < storageHooks.length; i++) { + instanceHooks[i] = storageHooks[i].create(newData); + instanceHooks[i].copy(data.getStorageHook((String) instanceHooks[i].getKey())); + } + newData.setStorageHooks(instanceHooks); + // get the old and new eclipse storage hooks + BaseStorageHook oldStorageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY); + BaseStorageHook newStorageHook = (BaseStorageHook) newData.getStorageHook(BaseStorageHook.KEY); + InputStream in = source.getInputStream(); + URL sourceURL = source.getURL(); + String protocol = sourceURL == null ? null : sourceURL.getProtocol(); + try { + if (in instanceof ReferenceInputStream) { + URL reference = ((ReferenceInputStream) in).getReference(); + if (!"file".equals(reference.getProtocol())) //$NON-NLS-1$ + throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_URL_CREATE_EXCEPTION, reference)); + // check to make sure we are not just trying to update to the same + // directory reference. This would be a no-op. + String path = reference.getPath(); + if (path.equals(oldStorageHook.getFileName())) + throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_SAME_REF_UPDATE, reference)); + newStorageHook.setReference(true); + newStorageHook.setFileName(path); + } else { + File genDir = newStorageHook.createGenerationDir(); + if (!genDir.exists()) + throw new BundleException(NLS.bind(AdaptorMsg.ADAPTOR_DIRECTORY_CREATE_EXCEPTION, genDir.getPath())); + newStorageHook.setReference(false); + newStorageHook.setFileName(BaseStorage.BUNDLEFILE_NAME); + File outFile = new File(genDir, newStorageHook.getFileName()); + if ("file".equals(protocol)) { //$NON-NLS-1$ + File inFile = new File(source.getURL().getPath()); + if (inFile.isDirectory()) { + AdaptorUtil.copyDir(inFile, outFile); + } else { + AdaptorUtil.readFile(in, outFile); + } + } else { + AdaptorUtil.readFile(in, outFile); + } + } + Dictionary manifest = storage.loadManifest(newData, true); + for (int i = 0; i < instanceHooks.length; i++) + instanceHooks[i].initialize(manifest); + } finally { + try { + if (in != null) + in.close(); + } catch (IOException ee) { + // nothing to do here + } + } + } catch (IOException e) { + throw new BundleException(AdaptorMsg.BUNDLE_READ_EXCEPTION, e); + } + + return (newData); + } + + /** + * Commit the change to persistent storage. + * + * @param postpone If true, the bundle's persistent + * storage cannot be immediately reclaimed. + * @throws BundleException If a failure occured modifiying peristent storage. + */ + + public void commit(boolean postpone) throws BundleException { + storage.processExtension(data, BaseStorage.EXTENSION_UNINSTALLED); // remove the old extension + storage.processExtension(newData, BaseStorage.EXTENSION_UPDATED); // update to the new one + try { + newData.setLastModified(System.currentTimeMillis()); + newData.save(); + } catch (IOException e) { + throw new BundleException(AdaptorMsg.ADAPTOR_STORAGE_EXCEPTION, e); + } + storage.updateState(newData, BundleEvent.UPDATED); + BaseStorageHook oldStorageHook = (BaseStorageHook) data.getStorageHook(BaseStorageHook.KEY); + try { + oldStorageHook.delete(postpone, BaseStorageHook.DEL_GENERATION); + } catch (IOException e) { + data.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, data.getBundle(), e); + } + } + + /** + * Undo the change to persistent storage. + * + * @throws BundleException If a failure occured modifiying peristent storage. + */ + public void undo() throws BundleException { + if (newData != null) { + BaseStorageHook newStorageHook = (BaseStorageHook) newData.getStorageHook(BaseStorageHook.KEY); + try { + if (newStorageHook != null) + newStorageHook.delete(false, BaseStorageHook.DEL_GENERATION); + } catch (IOException e) { + data.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, data.getBundle(), e); + } + } + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java new file mode 100644 index 000000000..7c4ee7a82 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright (c) 2005 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.internal.baseadaptor; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.*; +import java.security.cert.Certificate; +import java.util.Enumeration; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; +import org.eclipse.osgi.baseadaptor.loader.*; +import org.eclipse.osgi.framework.adaptor.BundleData; +import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; +import org.eclipse.osgi.framework.debug.Debug; + +/** + * The default implemention of <code>BaseClassLoader</code>. This implementation extends + * <code>ClassLoader</code>. + * @see BaseClassLoader + * @see ClasspathManager + */ +public class DefaultClassLoader extends ClassLoader implements BaseClassLoader { + /** + * A PermissionCollection for AllPermissions; shared across all ProtectionDomains when security is disabled + */ + protected static final PermissionCollection ALLPERMISSIONS; + static { + AllPermission allPerm = new AllPermission(); + ALLPERMISSIONS = allPerm.newPermissionCollection(); + if (ALLPERMISSIONS != null) + ALLPERMISSIONS.add(allPerm); + } + + protected ClassLoaderDelegate delegate; + protected ProtectionDomain domain; + protected ClasspathManager manager; + + /** + * Constructs a new DefaultClassLoader. + * @param parent the parent classloader + * @param delegate the delegate for this classloader + * @param domain the domain for this classloader + * @param bundledata the bundledata for this classloader + * @param classpath the classpath for this classloader + */ + public DefaultClassLoader(ClassLoader parent, ClassLoaderDelegate delegate, ProtectionDomain domain, BaseData bundledata, String[] classpath) { + super(parent); + this.delegate = delegate; + this.domain = domain; + this.manager = new ClasspathManager(bundledata, classpath, this); + } + + /** + * Loads a class for the bundle. First delegate.findClass(name) is called. + * The delegate will query the system class loader, bundle imports, bundle + * local classes, bundle hosts and fragments. The delegate will call + * BundleClassLoader.findLocalClass(name) to find a class local to this + * bundle. + * @param name the name of the class to load. + * @param resolve indicates whether to resolve the loaded class or not. + * @return The Class object. + * @throws ClassNotFoundException if the class is not found. + */ + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (Debug.DEBUG && Debug.DEBUG_LOADER) + Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ + try { + // Just ask the delegate. This could result in findLocalClass(name) being called. + Class clazz = delegate.findClass(name); + // resolve the class if asked to. + if (resolve) + resolveClass(clazz); + return (clazz); + } catch (Error e) { + if (Debug.DEBUG && Debug.DEBUG_LOADER) { + Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + Debug.printStackTrace(e); + } + throw e; + } catch (ClassNotFoundException e) { + // If the class is not found do not try to look for it locally. + // The delegate would have already done that for us. + if (Debug.DEBUG && Debug.DEBUG_LOADER) { + Debug.println("BundleClassLoader[" + delegate + "].loadClass(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + Debug.printStackTrace(e); + } + throw e; + } + } + + /** + * Gets a resource for the bundle. First delegate.findResource(name) is + * called. The delegate will query the system class loader, bundle imports, + * bundle local resources, bundle hosts and fragments. The delegate will + * call BundleClassLoader.findLocalResource(name) to find a resource local + * to this bundle. + * @param name The resource path to get. + * @return The URL of the resource or null if it does not exist. + */ + public URL getResource(String name) { + if (Debug.DEBUG && Debug.DEBUG_LOADER) { + Debug.println("BundleClassLoader[" + delegate + "].getResource(" + name + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + URL url = delegate.findResource(name); + if (url != null) + return (url); + + if (Debug.DEBUG && Debug.DEBUG_LOADER) { + Debug.println("BundleClassLoader[" + delegate + "].getResource(" + name + ") failed."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + return (null); + } + + /** + * Finds all resources with the specified name. This method must call + * delegate.findResources(name) to find all the resources. + * @param name The resource path to find. + * @return An Enumeration of all resources found or null if the resource. + * @throws IOException + */ + protected Enumeration findResources(String name) throws IOException { + return (delegate.findResources(name)); + } + + /** + * Finds a library for this bundle. Simply calls + * delegate.findLibrary(libname) to find the library. + * @param libname The library to find. + * @return The URL of the resource or null if it does not exist. + */ + protected String findLibrary(String libname) { + return delegate.findLibrary(libname); + } + + public ProtectionDomain getDomain() { + return domain; + } + + public ClasspathEntry createClassPathEntry(BundleFile bundlefile, ProtectionDomain cpDomain) { + return new ClasspathEntry(bundlefile, createProtectionDomain(bundlefile, cpDomain)); + } + + public Class defineClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry) { + return defineClass(name, classbytes, 0, classbytes.length, classpathEntry.getDomain()); + } + + public Class publicFindLoaded(String classname) { + return findLoadedClass(classname); + } + + public Object publicGetPackage(String pkgname) { + return getPackage(pkgname); + } + + public Object publicDefinePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase) { + return definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase); + } + + public void initialize() { + manager.initialize(); + } + + public URL findLocalResource(String resource) { + return manager.findLocalResource(resource); + } + + public Enumeration findLocalResources(String resource) { + return manager.findLocalResources(resource); + } + + public Class findLocalClass(String classname) throws ClassNotFoundException { + return manager.findLocalClass(classname); + } + + public void close() { + manager.close(); + } + + public void attachFragment(BundleData sourcedata, ProtectionDomain sourcedomain, String[] sourceclasspath) { + manager.attachFragment(sourcedata, sourcedomain, sourceclasspath); + } + + public ClassLoaderDelegate getDelegate() { + return delegate; + } + + /** + * Creates a ProtectionDomain which uses specified BundleFile and the permissions of the baseDomain + * @param bundlefile The source bundlefile the domain is for. + * @param baseDomain The source domain. + * @return a ProtectionDomain which uses specified BundleFile and the permissions of the baseDomain + */ + public static ProtectionDomain createProtectionDomain(BundleFile bundlefile, ProtectionDomain baseDomain) { + // create a protection domain which knows about the codesource for this classpath entry (bug 89904) + try { + // use the permissions supplied by the domain passed in from the framework + PermissionCollection permissions; + if (baseDomain != null) + permissions = baseDomain.getPermissions(); + else + // no domain specified. Better use a collection that has all permissions + // this is done just incase someone sets the security manager later + permissions = ALLPERMISSIONS; + return new ClasspathDomain(bundlefile.getBaseFile().toURL(), permissions); + } catch (MalformedURLException e) { + // Failed to create our own domain; just return the baseDomain + return baseDomain; + } + } + + /** + * Very simple protection domain that uses a URL to create a CodeSource for a ProtectionDomain + */ + protected static class ClasspathDomain extends ProtectionDomain { + public ClasspathDomain(URL codeLocation, PermissionCollection permissions) { + super(new CodeSource(codeLocation, (Certificate[]) null), permissions); + } + } + + public ClasspathManager getClasspathManager() { + return manager; + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DevClassLoadingHook.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DevClassLoadingHook.java new file mode 100644 index 000000000..b0befb8f8 --- /dev/null +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DevClassLoadingHook.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2006 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.internal.baseadaptor; + +import java.security.ProtectionDomain; +import java.util.ArrayList; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook; +import org.eclipse.osgi.baseadaptor.loader.*; +import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain; +import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; + +public class DevClassLoadingHook implements ClassLoadingHook, HookConfigurator { + + public byte[] processClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { + // Do nothing + return null; + } + + public boolean addClassPathEntry(ArrayList cpEntries, String cp, ClasspathManager hostmanager, BaseData sourcedata, ProtectionDomain sourcedomain) { + String[] devClassPath = !DevClassPathHelper.inDevelopmentMode() ? null : DevClassPathHelper.getDevClassPath(sourcedata.getSymbolicName()); + if (devClassPath == null || devClassPath.length == 0) + return false; // not in dev mode return + boolean result = false; + for (int i = 0; i < devClassPath.length; i++) { + if (ClasspathManager.addClassPathEntry(cpEntries, devClassPath[i], hostmanager, sourcedata, sourcedomain)) + result = true; + else { + // if in dev mode, try using the cp as an absolute path + ClasspathEntry entry = hostmanager.getExternalClassPath(devClassPath[i], sourcedata, sourcedomain); + if (entry != null){ + cpEntries.add(entry); + result = true; + } + } + } + + return result; + } + + public String findLibrary(BaseData data, String libName) { + // Do nothing + return null; + } + + public ClassLoader getBundleClassLoaderParent() { + // Do nothing + return null; + } + + public BaseClassLoader createClassLoader(ClassLoader parent, ClassLoaderDelegate delegate, BundleProtectionDomain domain, BaseData data, String[] bundleclasspath) { + // do nothing + return null; + } + + public void initializedClassLoader(BaseClassLoader baseClassLoader, BaseData data) { + // do nothing + } + + public void addHooks(HookRegistry hookRegistry) { + if (DevClassPathHelper.inDevelopmentMode()) + // only add dev classpath manager if in dev mode + hookRegistry.addClassLoadingHook(new DevClassLoadingHook()); + + } +} diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/DevClassPathHelper.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DevClassPathHelper.java index b027bfc1b..de565abbb 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/DevClassPathHelper.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/DevClassPathHelper.java @@ -8,7 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ -package org.eclipse.osgi.framework.adaptor.core; +package org.eclipse.osgi.internal.baseadaptor; import java.io.IOException; import java.io.InputStream; diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/ExternalMessages.properties b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/ExternalMessages.properties index d1d9a8e6d..d1d9a8e6d 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/ExternalMessages.properties +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/ExternalMessages.properties diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/InvalidVersion.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/InvalidVersion.java index 19670799a..a2edb6520 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/InvalidVersion.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/InvalidVersion.java @@ -9,7 +9,7 @@ * IBM Corporation - initial API and implementation *******************************************************************************/ -package org.eclipse.osgi.framework.adaptor.core; +package org.eclipse.osgi.internal.baseadaptor; import org.osgi.framework.Version; diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/StateManager.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/StateManager.java index 05df80888..7a039bab0 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/adaptor/core/StateManager.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/StateManager.java @@ -8,7 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ -package org.eclipse.osgi.framework.adaptor.core; +package org.eclipse.osgi.internal.baseadaptor; import java.io.File; import java.io.IOException; @@ -60,7 +60,6 @@ public class StateManager implements PlatformAdmin, Runnable { private StateImpl systemState; private StateObjectFactoryImpl factory; private long lastTimeStamp; - private BundleInstaller installer; private boolean cachedState = false; private File stateFile; private File lazyFile; @@ -270,25 +269,7 @@ public class StateManager implements PlatformAdmin, Runnable { * @see PlatformAdmin#commit(State) */ public synchronized void commit(State state) throws BundleException { - // no installer have been provided - commit not supported - if (installer == null) - throw new IllegalArgumentException("PlatformAdmin.commit() not supported"); //$NON-NLS-1$ - if (!(state instanceof UserState)) - throw new IllegalArgumentException("Wrong state implementation"); //$NON-NLS-1$ - if (state.getTimeStamp() != systemState.getTimeStamp()) - throw new BundleException(StateMsg.COMMIT_INVALID_TIMESTAMP); - StateDelta delta = state.compare(systemState); - BundleDelta[] changes = delta.getChanges(); - for (int i = 0; i < changes.length; i++) - if ((changes[i].getType() & BundleDelta.ADDED) > 0) - installer.installBundle(changes[i].getBundle()); - else if ((changes[i].getType() & BundleDelta.REMOVED) > 0) - installer.uninstallBundle(changes[i].getBundle()); - else if ((changes[i].getType() & BundleDelta.UPDATED) > 0) - installer.updateBundle(changes[i].getBundle()); - else { - // bug in StateDelta#getChanges - } + throw new IllegalArgumentException("PlatformAdmin.commit() not supported"); //$NON-NLS-1$ } /** @@ -309,23 +290,6 @@ public class StateManager implements PlatformAdmin, Runnable { return StateHelperImpl.getInstance(); } - /** - * Returns the bundle installer. - * @return the bundle installer - */ - public BundleInstaller getInstaller() { - return installer; - } - - /** - * Sets the bundle installer. The bundle installer will be used when a state is commited - * using the commit(State) method. - * @param installer the bundle installer - */ - public void setInstaller(BundleInstaller installer) { - this.installer = installer; - } - public void run() { long timeStamp = lastTimeStamp; // cache the original timestamp incase of updates while (true) { diff --git a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/SystemBundleData.java b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/SystemBundleData.java index 9fc001b34..36e9c6f19 100644 --- a/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/framework/internal/core/SystemBundleData.java +++ b/bundles/org.eclipse.osgi/defaultAdaptor/src/org/eclipse/osgi/internal/baseadaptor/SystemBundleData.java @@ -4,28 +4,31 @@ * 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; +package org.eclipse.osgi.internal.baseadaptor; import java.io.*; import java.net.URL; import java.util.Enumeration; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; import org.eclipse.osgi.framework.adaptor.*; -import org.eclipse.osgi.framework.adaptor.core.*; import org.eclipse.osgi.framework.debug.Debug; import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.internal.core.FrameworkProperties; import org.eclipse.osgi.framework.util.Headers; import org.osgi.framework.BundleException; -public class SystemBundleData extends AbstractBundleData { - public static final String OSGI_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$ +public class SystemBundleData extends BaseData { + private static final String OSGI_FRAMEWORK = "osgi.framework"; //$NON-NLS-1$ - public SystemBundleData(AbstractFrameworkAdaptor adaptor) throws BundleException { - super(adaptor, 0); + public SystemBundleData(BaseAdaptor adaptor) throws BundleException { + super(0, adaptor); File osgiBase = getOsgiBase(); createBundleFile(osgiBase); manifest = createManifest(osgiBase); @@ -34,7 +37,7 @@ public class SystemBundleData extends AbstractBundleData { } private File getOsgiBase() { - String frameworkLocation = FrameworkProperties.getProperty(OSGI_FRAMEWORK); + String frameworkLocation = FrameworkProperties.getProperty(SystemBundleData.OSGI_FRAMEWORK); if (frameworkLocation != null) // TODO assumes the location is a file URL return new File(frameworkLocation.substring(5)); @@ -54,43 +57,27 @@ public class SystemBundleData extends AbstractBundleData { private Headers createManifest(File osgiBase) throws BundleException { InputStream in = null; - if (osgiBase != null && osgiBase.exists()) { + if (osgiBase != null && osgiBase.exists()) try { - BundleEntry entry = baseBundleFile.getEntry(Constants.OSGI_BUNDLE_MANIFEST); + BundleEntry entry = getBundleFile().getEntry(Constants.OSGI_BUNDLE_MANIFEST); if (entry != null) in = entry.getInputStream(); } catch (IOException e) { // do nothing here. in == null } - } // If we cannot find the Manifest file from the baseBundleFile then // search for the manifest as a classloader resource // This allows an adaptor to package the SYSTEMBUNDLE.MF file in a jar. - if (in == null) { + if (in == null) in = getManifestAsResource(); - } - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - if (in == null) { + if (Debug.DEBUG && Debug.DEBUG_GENERAL) + if (in == null) Debug.println("Unable to find system bundle manifest " + Constants.OSGI_BUNDLE_MANIFEST); //$NON-NLS-1$ - } - } if (in == null) throw new BundleException(AdaptorMsg.SYSTEMBUNDLE_MISSING_MANIFEST); - Headers systemManifest = Headers.parseManifest(in); - // now get any extra packages and services that the adaptor wants - // to export and merge this into the system bundle's manifest - String exportPackages = adaptor.getExportPackages(); - String exportServices = adaptor.getExportServices(); - String providePackages = adaptor.getProvidePackages(); - if (exportPackages != null) - appendManifestValue(systemManifest, Constants.EXPORT_PACKAGE, exportPackages); - if (exportServices != null) - appendManifestValue(systemManifest, Constants.EXPORT_SERVICE, exportServices); - if (providePackages != null) - appendManifestValue(systemManifest, Constants.PROVIDE_PACKAGE, providePackages); - return systemManifest; + return Headers.parseManifest(in); } private InputStream getManifestAsResource() { @@ -115,26 +102,16 @@ public class SystemBundleData extends AbstractBundleData { return null; } - private void appendManifestValue(Headers systemManifest, String header, String append) { - String newValue = (String) systemManifest.get(header); - if (newValue == null) { - newValue = append; - } else { - newValue += "," + append; //$NON-NLS-1$ - } - systemManifest.set(header, newValue, true); - } - private void createBundleFile(File osgiBase) { if (osgiBase != null) try { - baseBundleFile = adaptor.createBundleFile(osgiBase, this); + bundleFile = getAdaptor().createBundleFile(osgiBase, this); } catch (IOException e) { // should not happen } else - baseBundleFile = new BundleFile(osgiBase) { - public File getFile(String path) { + bundleFile = new BundleFile(osgiBase) { + public File getFile(String path, boolean nativeCode) { return null; } @@ -162,7 +139,7 @@ public class SystemBundleData extends AbstractBundleData { private void setMetaData() throws BundleException { setLocation(Constants.SYSTEM_BUNDLE_LOCATION); - loadFromManifest(); + BaseStorageHook.loadManifest(this, manifest); } public BundleClassLoader createClassLoader(ClassLoaderDelegate delegate, BundleProtectionDomain domain, String[] bundleclasspath) { @@ -197,7 +174,4 @@ public class SystemBundleData extends AbstractBundleData { // do nothing } - public String[] getBundleSigners() { - return null; // system bundle cannot be signed - } } diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/ADAPTOR.MF b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/ADAPTOR.MF deleted file mode 100644 index 9537d5ea2..000000000 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/ADAPTOR.MF +++ /dev/null @@ -1,8 +0,0 @@ -Export-Service: - org.eclipse.osgi.framework.log.FrameworkLog, - org.eclipse.osgi.service.environment.EnvironmentInfo, - org.eclipse.osgi.service.pluginconversion.PluginConverter, - org.eclipse.osgi.service.datalocation.Location, - org.eclipse.osgi.service.runnable, - org.eclipse.osgi.service.urlconversion.URLConverter, - org.eclipse.osgi.service.localization.BundleLocalization diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptor.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptor.java deleted file mode 100644 index 8e10d4074..000000000 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptor.java +++ /dev/null @@ -1,982 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2006 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.core.runtime.adaptor; - -import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.*; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.SAXParserFactory; -import org.eclipse.core.runtime.internal.adaptor.*; -import org.eclipse.core.runtime.internal.stats.StatsManager; -import org.eclipse.osgi.framework.adaptor.*; -import org.eclipse.osgi.framework.adaptor.core.*; -import org.eclipse.osgi.framework.console.CommandProvider; -import org.eclipse.osgi.framework.debug.Debug; -import org.eclipse.osgi.framework.debug.FrameworkDebugOptions; -import org.eclipse.osgi.framework.internal.core.Constants; -import org.eclipse.osgi.framework.internal.core.FrameworkProperties; -import org.eclipse.osgi.framework.log.FrameworkLog; -import org.eclipse.osgi.framework.log.FrameworkLogEntry; -import org.eclipse.osgi.service.datalocation.Location; -import org.eclipse.osgi.service.pluginconversion.PluginConverter; -import org.eclipse.osgi.service.resolver.*; -import org.eclipse.osgi.service.runnable.ApplicationLauncher; -import org.eclipse.osgi.service.urlconversion.URLConverter; -import org.eclipse.osgi.storagemanager.ManagedOutputStream; -import org.eclipse.osgi.storagemanager.StorageManager; -import org.eclipse.osgi.util.NLS; -import org.osgi.framework.*; - -/** - * The FrameworkAdaptor implementation used to launch to OSGi framework for Eclipse. - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -public class EclipseAdaptor extends AbstractFrameworkAdaptor { - /** System property used to clean the osgi configuration area */ - public static final String PROP_CLEAN = "osgi.clean"; //$NON-NLS-1$ - /** System property used to prevent VM exit when unexpected errors occur */ - public static final String PROP_EXITONERROR = "eclipse.exitOnError"; //$NON-NLS-1$ - /** System property used to determine whether State saver needs to be enabled */ - public static final String PROP_ENABLE_STATE_SAVER = "eclipse.enableStateSaver"; //$NON-NLS-1$ - - static final String F_LOG = ".log"; //$NON-NLS-1$ - /** Manifest header used to specify the plugin class */ - // TODO rename it to Eclipse-PluginClass - public static final String PLUGIN_CLASS = "Plugin-Class"; //$NON-NLS-1$ - /** Manifest header used to specify the lazy start properties of a bundle */ - public static final String ECLIPSE_LAZYSTART = "Eclipse-LazyStart"; //$NON-NLS-1$ - /** An Eclipse-LazyStart attribute used to specify exception classes for auto start */ - public static final String ECLIPSE_LAZYSTART_EXCEPTIONS = "exceptions"; //$NON-NLS-1$ - /** - * Manifest header used to specify the auto start properties of a bundle - * @deprecated use {@link #ECLIPSE_LAZYSTART} - */ - public static final String ECLIPSE_AUTOSTART = "Eclipse-AutoStart"; //$NON-NLS-1$ - /** - * @deprecated use {@link #ECLIPSE_LAZYSTART_EXCEPTIONS} - */ - public static final String ECLIPSE_AUTOSTART_EXCEPTIONS = ECLIPSE_LAZYSTART_EXCEPTIONS; - /** The SAX factory name */ - public static final String SAXFACTORYNAME = "javax.xml.parsers.SAXParserFactory"; //$NON-NLS-1$ - /** The DOM factory name */ - public static final String DOMFACTORYNAME = "javax.xml.parsers.DocumentBuilderFactory"; //$NON-NLS-1$ - - private static final String RUNTIME_ADAPTOR = FRAMEWORK_SYMBOLICNAME + "/eclipseadaptor"; //$NON-NLS-1$ - - private static final String OPTION_PLATFORM_ADMIN = RUNTIME_ADAPTOR + "/debug/platformadmin"; //$NON-NLS-1$ - - private static final String OPTION_PLATFORM_ADMIN_RESOLVER = RUNTIME_ADAPTOR + "/debug/platformadmin/resolver"; //$NON-NLS-1$ - - private static final String OPTION_MONITOR_PLATFORM_ADMIN = RUNTIME_ADAPTOR + "/resolver/timing"; //$NON-NLS-1$ - - private static final String OPTION_RESOLVER_READER = RUNTIME_ADAPTOR + "/resolver/reader/timing"; //$NON-NLS-1$ - - private static final String OPTION_CONVERTER = RUNTIME_ADAPTOR + "/converter/debug"; //$NON-NLS-1$ - - private static final String OPTION_LOCATION = RUNTIME_ADAPTOR + "/debug/location"; //$NON-NLS-1$ - - /** The current bundle data version */ - public static final byte BUNDLEDATA_VERSION = 16; - /** The NULL tag used in bundle data */ - public static final byte NULL = 0; - /** The OBJECT tag used in bundle data */ - public static final byte OBJECT = 1; - - private static EclipseAdaptor instance; - - private byte cacheVersion; - - private long timeStamp = 0; - - // assume a file: installURL - private String installPath = null; - - private boolean exitOnError = true; - - private BundleStopper stopper; - - private StorageManager storageManager; - - private boolean reinitialize = false; - - private StateSaver stateSaver = null; - private boolean noXML = false; - - /** - * Should be instantiated only by the framework (through reflection). - * @param args the adaptor arguments - */ - public EclipseAdaptor(String[] args) { - super(args); - instance = this; - setDebugOptions(); - } - - /** - * Gets the default instance - * @return the default instance - */ - public static EclipseAdaptor getDefault() { - return instance; - } - - private FrameworkLog createPerformanceLog() { - String logFileProp = FrameworkProperties.getProperty(EclipseStarter.PROP_LOGFILE); - if (logFileProp != null) { - int lastSlash = logFileProp.lastIndexOf(File.separatorChar); - if (lastSlash > 0) { - String logFile = logFileProp.substring(0, lastSlash + 1) + "performance.log"; //$NON-NLS-1$ - return new EclipseLog(new File(logFile)); - } - } - //if all else fails, write to std err - return new EclipseLog(new PrintWriter(System.err)); - } - - /** - * @see FrameworkAdaptor#initialize(EventPublisher) - */ - public void initialize(EventPublisher publisher) { - if (Boolean.valueOf(FrameworkProperties.getProperty(EclipseAdaptor.PROP_CLEAN)).booleanValue()) - cleanOSGiCache(); - boolean readOnlyConfiguration = LocationManager.getConfigurationLocation().isReadOnly(); - storageManager = initStorageManager(LocationManager.getOSGiConfigurationDir(), readOnlyConfiguration ? "none" : null, readOnlyConfiguration); //$NON-NLS-1$ - readHeaders(); - super.initialize(publisher); - // default the bootdelegation to all packages - if (FrameworkProperties.getProperty(Constants.OSGI_BOOTDELEGATION) == null && !Constants.OSGI_BOOTDELEGATION_NONE.equals(FrameworkProperties.getProperty(Constants.OSGI_JAVA_PROFILE_BOOTDELEGATION))) - FrameworkProperties.setProperty(Constants.OSGI_BOOTDELEGATION, "*"); //$NON-NLS-1$ - if (FrameworkProperties.getProperty(Constants.ECLIPSE_EE_INSTALL_VERIFY) == null) - FrameworkProperties.setProperty(Constants.ECLIPSE_EE_INSTALL_VERIFY, "false"); //$NON-NLS-1$ - // we need to set the install path as soon as possible so we can determine - // the absolute location of install relative URLs - Location installLoc = LocationManager.getInstallLocation(); - if (installLoc != null) { - URL installURL = installLoc.getURL(); - // assume install URL is file: based - installPath = installURL.getPath(); - } - } - - /** - * @see AbstractFrameworkAdaptor#initializeMetadata() - */ - public void initializeMetadata() { - // do nothing here; metadata is already initialized by readHeaders. - } - - protected void initBundleStoreRootDir() { - File configurationLocation = LocationManager.getOSGiConfigurationDir(); - if (configurationLocation != null) { - bundleStoreRootDir = new File(configurationLocation, LocationManager.BUNDLES_DIR); - bundleStore = bundleStoreRootDir.getAbsolutePath(); - } else { - // last resort just default to "bundles" - bundleStore = LocationManager.BUNDLES_DIR; - bundleStoreRootDir = new File(bundleStore); - } - - /* store bundleStore back into adaptor properties for others to see */ - properties.put(BUNDLE_STORE, bundleStoreRootDir.getAbsolutePath()); - } - - protected FrameworkLog createFrameworkLog() { - if (frameworkLog != null) - return frameworkLog; - return EclipseStarter.createFrameworkLog(); - } - - private File[] findStateFiles() { - if (reinitialize) - return new File[2]; // return null enties to indicate reinitialize - File stateFile = null; - File lazyFile = null; - try { - stateFile = storageManager.lookup(LocationManager.STATE_FILE, false); - lazyFile = storageManager.lookup(LocationManager.LAZY_FILE, false); - } catch (IOException ex) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Error reading state file " + ex.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(ex); - } - } - //if it does not exist, try to read it from the parent - if (stateFile == null || !stateFile.isFile()) { // NOTE this check is redundant since it - // is done in StateManager, however it - // is more convenient to have it here - Location parentConfiguration = null; - Location currentConfiguration = LocationManager.getConfigurationLocation(); - if (currentConfiguration != null && (parentConfiguration = currentConfiguration.getParentLocation()) != null) { - try { - File stateLocationDir = new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME); - StorageManager newStorageManager = initStorageManager(stateLocationDir, "none", true); //$NON-NLS-1$); - stateFile = newStorageManager.lookup(LocationManager.STATE_FILE, false); - lazyFile = newStorageManager.lookup(LocationManager.LAZY_FILE, false); - } catch (IOException ex) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Error reading state file " + ex.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(ex); - } - } - } else { - try { - //it did not exist in either place, so create it in the original location - if (canWrite()) { - stateFile = storageManager.lookup(LocationManager.STATE_FILE, true); - lazyFile = storageManager.lookup(LocationManager.LAZY_FILE, true); - } - } catch (IOException ex) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Error reading state file " + ex.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(ex); - } - } - } - } - return new File[] {stateFile, lazyFile}; - } - - protected StateManager createStateManager() { - File[] stateFiles = findStateFiles(); - File stateFile = stateFiles[0]; - File lazyFile = stateFiles[1]; - - stateManager = new StateManager(stateFile, lazyFile, context, timeStamp); - stateManager.setInstaller(new EclipseBundleInstaller(context)); - State systemState = null; - if (!invalidState) { - systemState = stateManager.readSystemState(); - if (systemState != null) - return stateManager; - } - systemState = stateManager.createSystemState(); - Bundle[] installedBundles = context.getBundles(); - if (installedBundles == null) - return stateManager; - StateObjectFactory factory = stateManager.getFactory(); - for (int i = 0; i < installedBundles.length; i++) { - Bundle toAdd = installedBundles[i]; - try { - Dictionary toAddManifest = toAdd.getHeaders(""); //$NON-NLS-1$ - // if this is a cached manifest need to get the real one - if (toAddManifest instanceof CachedManifest) - toAddManifest = ((CachedManifest) toAddManifest).getManifest(); - BundleDescription newDescription = factory.createBundleDescription(systemState, toAddManifest, toAdd.getLocation(), toAdd.getBundleId()); - systemState.addBundle(newDescription); - } catch (BundleException be) { - // just ignore bundle datas with invalid manifests - } - } - // we need the state resolved - systemState.setTimeStamp(timeStamp); - systemState.resolve(); - invalidState = false; - return stateManager; - } - - public void shutdownStateManager() { - if (stateSaver != null) - stateSaver.shutdown(); - saveStateToFile(true); - // calling stateManager.shutdown from saveStateToFile will also stop the data manager - // but we may not call that method if the configuration is read-only or if the state has not changed, - // so we call here also just in case. - stateManager.stopDataManager(); - } - - void saveStateToFile(boolean shutdown) { - if (!canWrite() || !stateManager.saveNeeded()) - return; - try { - File stateTmpFile = File.createTempFile(LocationManager.STATE_FILE, ".new", LocationManager.getOSGiConfigurationDir()); //$NON-NLS-1$ - File lazyTmpFile = File.createTempFile(LocationManager.LAZY_FILE, ".new", LocationManager.getOSGiConfigurationDir()); //$NON-NLS-1$ - if (shutdown) - stateManager.shutdown(stateTmpFile, lazyTmpFile); - else - synchronized (stateManager) { - stateManager.update(stateTmpFile, lazyTmpFile); - } - storageManager.lookup(LocationManager.STATE_FILE, true); - storageManager.lookup(LocationManager.LAZY_FILE, true); - storageManager.update(new String[] {LocationManager.STATE_FILE, LocationManager.LAZY_FILE}, new String[] {stateTmpFile.getName(), lazyTmpFile.getName()}); - } catch (IOException e) { - frameworkLog.log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e)); - } - } - - private void cleanOSGiCache() { - File osgiConfig = LocationManager.getOSGiConfigurationDir(); - if (!rm(osgiConfig)) { - // TODO log error? - } - } - - private void readHeaders() { - InputStream bundleDataStream = findBundleDataFile(); - if (bundleDataStream == null) - return; - - try { - DataInputStream in = new DataInputStream(new BufferedInputStream(bundleDataStream)); - try { - cacheVersion = in.readByte(); - if (cacheVersion == BUNDLEDATA_VERSION) { - timeStamp = in.readLong(); - initialBundleStartLevel = in.readInt(); - nextId = in.readLong(); - } - } finally { - in.close(); - } - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Error reading framework metadata: " + e.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(e); - } - } - } - - public AdaptorElementFactory getElementFactory() { - if (elementFactory == null) - elementFactory = new EclipseElementFactory(); - return elementFactory; - } - - public void frameworkStart(BundleContext aContext) throws BundleException { - // EnvironmentInfo has to be initialized first to compute defaults for system context (see bug 88925) - EclipseEnvironmentInfo.getDefault(); - // must register the xml parser and initialize the plugin converter - // instance first because we may need it when creating the statemanager - // in super.frameworkStart(context) - registerEndorsedXMLParser(aContext); - PluginConverter converter = new PluginConverterImpl(this, aContext); - super.frameworkStart(aContext); - Bundle bundle = aContext.getBundle(); - Location location; - - // System property can be set to enable state saver or not. - if (Boolean.valueOf(FrameworkProperties.getProperty(PROP_ENABLE_STATE_SAVER, "true")).booleanValue()) //$NON-NLS-1$ - stateSaver = new StateSaver(); - - // Less than optimal reference to EclipseStarter here. Not sure how we - // can make the location - // objects available. They are needed very early in EclipseStarter but - // these references tie the adaptor to that starter. - location = LocationManager.getUserLocation(); - Hashtable locationProperties = new Hashtable(1); - if (location != null) { - locationProperties.put("type", LocationManager.PROP_USER_AREA); //$NON-NLS-1$ - aContext.registerService(Location.class.getName(), location, locationProperties); - } - location = LocationManager.getInstanceLocation(); - if (location != null) { - locationProperties.put("type", LocationManager.PROP_INSTANCE_AREA); //$NON-NLS-1$ - aContext.registerService(Location.class.getName(), location, locationProperties); - } - location = LocationManager.getConfigurationLocation(); - if (location != null) { - locationProperties.put("type", LocationManager.PROP_CONFIG_AREA); //$NON-NLS-1$ - aContext.registerService(Location.class.getName(), location, locationProperties); - } - location = LocationManager.getInstallLocation(); - if (location != null) { - locationProperties.put("type", LocationManager.PROP_INSTALL_AREA); //$NON-NLS-1$ - aContext.registerService(Location.class.getName(), location, locationProperties); - } - - Dictionary urlProperties = new Hashtable(); - urlProperties.put("protocol", new String[] {"bundleentry", "bundleresource"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - aContext.registerService(URLConverter.class.getName(), new URLConverterImpl(), urlProperties); - - register(org.eclipse.osgi.service.environment.EnvironmentInfo.class.getName(), EclipseEnvironmentInfo.getDefault(), bundle); - register(PlatformAdmin.class.getName(), stateManager, bundle); - register(PluginConverter.class.getName(), converter, bundle); - register(CommandProvider.class.getName(), new EclipseCommandProvider(aContext), bundle); - register(FrameworkLog.class.getName(), getFrameworkLog(), bundle); - registerPerformanceLog(bundle); - register(org.eclipse.osgi.service.localization.BundleLocalization.class.getName(), new BundleLocalizationImpl(), bundle); - } - - private void registerPerformanceLog(Bundle bundle) { - Object service = createPerformanceLog(); - String serviceName = FrameworkLog.class.getName(); - Hashtable serviceProperties = new Hashtable(7); - Dictionary headers = bundle.getHeaders(); - - serviceProperties.put(Constants.SERVICE_VENDOR, headers.get(Constants.BUNDLE_VENDOR)); - serviceProperties.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE)); - serviceProperties.put(Constants.SERVICE_PID, bundle.getBundleId() + '.' + service.getClass().getName()); - serviceProperties.put(FrameworkLog.SERVICE_PERFORMANCE, Boolean.TRUE.toString()); - - context.registerService(serviceName, service, serviceProperties); - } - - private void setDebugOptions() { - FrameworkDebugOptions options = FrameworkDebugOptions.getDefault(); - // may be null if debugging is not enabled - if (options == null) - return; - StateManager.DEBUG = options != null; - StateManager.DEBUG_READER = options.getBooleanOption(OPTION_RESOLVER_READER, false); - StateManager.MONITOR_PLATFORM_ADMIN = options.getBooleanOption(OPTION_MONITOR_PLATFORM_ADMIN, false); - StateManager.DEBUG_PLATFORM_ADMIN = options.getBooleanOption(OPTION_PLATFORM_ADMIN, false); - StateManager.DEBUG_PLATFORM_ADMIN_RESOLVER = options.getBooleanOption(OPTION_PLATFORM_ADMIN_RESOLVER, false); - PluginConverterImpl.DEBUG = options.getBooleanOption(OPTION_CONVERTER, false); - BasicLocation.DEBUG = options.getBooleanOption(OPTION_LOCATION, false); - } - - private void registerEndorsedXMLParser(BundleContext bc) { - try { - Class.forName(SAXFACTORYNAME); - bc.registerService(SAXFACTORYNAME, new SaxParsingService(), new Hashtable()); - Class.forName(DOMFACTORYNAME); - bc.registerService(DOMFACTORYNAME, new DomParsingService(), new Hashtable()); - } catch (ClassNotFoundException e) { - // In case the JAXP API is not on the boot classpath - noXML = true; - if (Debug.DEBUG && Debug.DEBUG_ENABLED) { - String message = EclipseAdaptorMsg.ECLIPSE_ADAPTOR_ERROR_XML_SERVICE; - getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null)); - } - } - } - - private class SaxParsingService implements ServiceFactory { - public Object getService(Bundle bundle, ServiceRegistration registration) { - return SAXParserFactory.newInstance(); - } - - public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { - // Do nothing. - } - } - - private class DomParsingService implements ServiceFactory { - public Object getService(Bundle bundle, ServiceRegistration registration) { - return DocumentBuilderFactory.newInstance(); - } - - public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { - // Do nothing. - } - } - - public boolean canWrite() { - return !storageManager.isReadOnly(); - } - - public void frameworkStop(BundleContext aContext) throws BundleException { - saveMetaData(); - super.frameworkStop(aContext); - printStats(); - if (!noXML) - PluginParser.releaseXMLParsing(); - storageManager.close(); - } - - private void printStats() { - FrameworkDebugOptions debugOptions = FrameworkDebugOptions.getDefault(); - if (debugOptions == null) - return; - String registryParsing = debugOptions.getOption("org.eclipse.core.runtime/registry/parsing/timing/value"); //$NON-NLS-1$ - if (registryParsing != null) - EclipseAdaptorMsg.debug("Time spent in registry parsing: " + registryParsing); //$NON-NLS-1$ - String packageAdminResolution = debugOptions.getOption("debug.packageadmin/timing/value"); //$NON-NLS-1$ - if (packageAdminResolution != null) - System.out.println("Time spent in package admin resolve: " + packageAdminResolution); //$NON-NLS-1$ - String constraintResolution = debugOptions.getOption("org.eclipse.core.runtime.adaptor/resolver/timing/value"); //$NON-NLS-1$ - if (constraintResolution != null) - System.out.println("Time spent resolving the dependency system: " + constraintResolution); //$NON-NLS-1$ - } - - private InputStream findBundleDataFile() { - if (reinitialize) - return null; // return null to indicate we are reinitializing - InputStream bundleDataStream = null; - try { - bundleDataStream = storageManager.getInputStream(LocationManager.BUNDLE_DATA_FILE); - } catch (IOException ex) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Error reading framework metadata: " + ex.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(ex); - } - } - if (bundleDataStream == null) { - Location currentConfiguration = LocationManager.getConfigurationLocation(); - Location parentConfiguration = null; - if (currentConfiguration != null && (parentConfiguration = currentConfiguration.getParentLocation()) != null) { - try { - File bundledataLocationDir = new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME); - StorageManager newStorageManager = initStorageManager(bundledataLocationDir, "none", true); //$NON-NLS-1$ - bundleDataStream = newStorageManager.getInputStream(LocationManager.BUNDLE_DATA_FILE); - newStorageManager.close(); - } catch (MalformedURLException e1) { - // This will not happen since all the URLs are derived by us - // and we are GODS! - } catch (IOException e1) { - // That's ok we will regenerate the .bundleData - } - } - } - return bundleDataStream; - } - - /** - * @see org.eclipse.osgi.framework.adaptor.FrameworkAdaptor#getInstalledBundles() - */ - public BundleData[] getInstalledBundles() { - InputStream bundleDataStream = findBundleDataFile(); - if (bundleDataStream == null) - return null; - - try { - DataInputStream in = new DataInputStream(new BufferedInputStream(bundleDataStream)); - try { - byte version = in.readByte(); - if (version != BUNDLEDATA_VERSION) - return null; - // skip timeStamp - was read by readHeaders - in.readLong(); - in.readInt(); - in.readLong(); - - int bundleCount = in.readInt(); - ArrayList result = new ArrayList(bundleCount); - long id = -1; - boolean bundleDiscarded = false; - for (int i = 0; i < bundleCount; i++) { - try { - id = in.readLong(); - if (id != 0) { - EclipseBundleData data = (EclipseBundleData) getElementFactory().createBundleData(this, id); - loadMetaDataFor(data, in, version); - data.initializeExistingBundle(); - if (Debug.DEBUG && Debug.DEBUG_GENERAL) - Debug.println("BundleData created: " + data); //$NON-NLS-1$ - processExtension(data, EXTENSION_INITIALIZE); - result.add(data); - } - } catch (NumberFormatException e) { - // should never happen - bundleDiscarded = true; - } catch (BundleException e) { - // should never happen - bundleDiscarded = true; - } catch (IOException e) { - bundleDiscarded = true; - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Error reading framework metadata: " + e.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(e); - } - } - } - if (bundleDiscarded) - FrameworkProperties.setProperty(EclipseStarter.PROP_REFRESH_BUNDLES, "true"); //$NON-NLS-1$ - return (BundleData[]) result.toArray(new BundleData[result.size()]); - } finally { - in.close(); - } - } catch (IOException e) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Error reading framework metadata: " + e.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(e); - } - } - return null; - } - - /** - * Loads the meta data for the specified bundle data - * @param data the bundle data to load meta data for - * @param in the stream to read the meta data from - * @param version the version of data being read - * @throws IOException when an io error occurs reading the metadata - */ - protected void loadMetaDataFor(EclipseBundleData data, DataInputStream in, byte version) throws IOException { - byte flag = in.readByte(); - if (flag == NULL) - return; - data.setLocation(readString(in, false)); - data.setFileName(readString(in, false)); - data.setSymbolicName(readString(in, false)); - data.setVersion(loadVersion(in)); - data.setActivator(readString(in, false)); - data.setAutoStart(in.readBoolean()); - int exceptionsCount = in.readInt(); - String[] autoStartExceptions = exceptionsCount > 0 ? new String[exceptionsCount] : null; - for (int i = 0; i < exceptionsCount; i++) - autoStartExceptions[i] = in.readUTF(); - data.setAutoStartExceptions(autoStartExceptions); - data.hasPackageInfo = in.readBoolean(); - data.buddyList = readString(in, false); - data.registeredBuddyList = readString(in, false); - data.setPluginClass(readString(in, false)); - data.setClassPathString(readString(in, false)); - data.setNativePaths(readString(in, false)); - data.setExecutionEnvironment(readString(in, false)); - data.setDynamicImports(readString(in, false)); - data.setGeneration(in.readInt()); - data.setStartLevel(in.readInt()); - data.setStatus(in.readInt()); - data.setReference(in.readBoolean()); - data.setManifestTimeStamp(in.readLong()); - data.setManifestType(in.readByte()); - data.setLastModified(in.readLong()); - data.setType(in.readInt()); - // TODO should we rearrange the isRefernce data before the fileName data? - // this step is done at the end because the FileName data is read before the isReference data - if (data.isReference()) { - // fileName for bundles installed with reference URLs is stored relative to the install location - File storedPath = new File(data.getFileName()); - if (!storedPath.isAbsolute()) - // make sure it has the absolute location instead - data.setFileName(new FilePath(installPath + data.getFileName()).toString()); - } - data.setDirty(false); - } - - private Version loadVersion(DataInputStream in) throws IOException { - String versionString = readString(in, false); - try { - return Version.parseVersion(versionString); - } catch (IllegalArgumentException e) { - return new InvalidVersion(versionString); - } - } - - /** - * Saves the metadata for the specified bundle data. This method only marks the bundle data - * as dirty if the bundle is not auto started. The bundle data is not persisted until the - * framework is shutdown. - * @param data - * @throws IOException - */ - public void saveMetaDataFor(EclipseBundleData data) throws IOException { - if (data.isDirty()) { - timeStamp--; // Change the value of the timeStamp, as a marker that something changed. - requestSave(); - } - } - - public void setInitialBundleStartLevel(int value) { - super.setInitialBundleStartLevel(value); - // Change the value of the timeStamp, as a marker that something changed. - timeStamp--; - requestSave(); - } - - public void persistNextBundleID(long value) { - // Do nothing the timeStamp will have changed because the state will be - // updated. - } - - /** - * Saves the metadata for the specified bundle data. - * @param data the bundle data - * @param out the stream to save the metadata to - * @throws IOException when an io error occurs saving the metadata - */ - protected void saveMetaDataFor(BundleData data, DataOutputStream out) throws IOException { - if (data.getBundleID() == 0 || !(data instanceof AbstractBundleData)) { - out.writeByte(NULL); - return; - } - EclipseBundleData bundleData = (EclipseBundleData) data; - out.writeByte(OBJECT); - writeStringOrNull(out, bundleData.getLocation()); - String storedFileName = bundleData.isReference() ? new FilePath(installPath).makeRelative(new FilePath(bundleData.getFileName())) : bundleData.getFileName(); - writeStringOrNull(out, storedFileName); - writeStringOrNull(out, bundleData.getSymbolicName()); - writeStringOrNull(out, bundleData.getVersion().toString()); - writeStringOrNull(out, bundleData.getActivator()); - out.writeBoolean(bundleData.isAutoStart()); - String[] autoStartExceptions = bundleData.getAutoStartExceptions(); - if (autoStartExceptions == null) - out.writeInt(0); - else { - out.writeInt(autoStartExceptions.length); - for (int i = 0; i < autoStartExceptions.length; i++) - out.writeUTF(autoStartExceptions[i]); - } - out.writeBoolean(bundleData.hasPackageInfo); - writeStringOrNull(out, bundleData.buddyList); - writeStringOrNull(out, bundleData.registeredBuddyList); - writeStringOrNull(out, bundleData.getPluginClass()); - writeStringOrNull(out, bundleData.getClassPathString()); - writeStringOrNull(out, bundleData.getNativePathsString()); - writeStringOrNull(out, bundleData.getExecutionEnvironment()); - writeStringOrNull(out, bundleData.getDynamicImports()); - out.writeInt(bundleData.getGeneration()); - out.writeInt(bundleData.getStartLevel()); - out.writeInt(bundleData.getPersistentStatus()); - out.writeBoolean(bundleData.isReference()); - out.writeLong(bundleData.getManifestTimeStamp()); - out.writeByte(bundleData.getManifestType()); - out.writeLong(bundleData.getLastModified()); - out.writeInt(bundleData.getType()); - } - - private String readString(DataInputStream in, boolean intern) throws IOException { - byte type = in.readByte(); - if (type == NULL) - return null; - return intern ? in.readUTF().intern() : in.readUTF(); - } - - private void writeStringOrNull(DataOutputStream out, String string) throws IOException { - if (string == null) - out.writeByte(NULL); - else { - out.writeByte(OBJECT); - out.writeUTF(string); - } - } - - /** - * Persists the bundle data for all bundles installed in the framework. - */ - public void saveMetaData() { - // the cache and the state match - if (!canWrite() | timeStamp == stateManager.getSystemState().getTimeStamp()) - return; - try { - ManagedOutputStream fmos = storageManager.getOutputStream(LocationManager.BUNDLE_DATA_FILE); - DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fmos)); - boolean error = true; - try { - out.writeByte(BUNDLEDATA_VERSION); - out.writeLong(stateManager.getSystemState().getTimeStamp()); - out.writeInt(initialBundleStartLevel); - out.writeLong(nextId); - Bundle[] bundles = context.getBundles(); - out.writeInt(bundles.length); - for (int i = 0; i < bundles.length; i++) { - long id = bundles[i].getBundleId(); - out.writeLong(id); - if (id != 0) { - BundleData data = ((org.eclipse.osgi.framework.internal.core.AbstractBundle) bundles[i]).getBundleData(); - saveMetaDataFor(data, out); - } - } - out.close(); - // update the 'timeStamp' after the changed Meta data is saved. - timeStamp = stateManager.getSystemState().getTimeStamp(); - error = false; - } finally { - // if something happens, don't close a corrupt file - if (error) { - fmos.abort(); - try { - out.close(); - } catch (IOException e) {/*ignore*/ - } - } - } - } catch (IOException e) { - frameworkLog.log(new FrameworkEvent(FrameworkEvent.ERROR, context.getBundle(), e)); - return; - } - } - - public BundleWatcher getBundleWatcher() { - return StatsManager.getDefault(); - } - - /** - * Returns the system bundle context - * @return the system bundle context - */ - protected BundleContext getContext() { - return context; - } - - public void frameworkStopping(BundleContext aContext) { - super.frameworkStopping(aContext); - // Shutdown the ApplicationLauncher service if it is available. - ServiceReference launcherRef = aContext.getServiceReference(ApplicationLauncher.class.getName()); - if (launcherRef != null) { - ApplicationLauncher launcher = (ApplicationLauncher) aContext.getService(launcherRef); - // this will force a currently running application to stop. - launcher.shutdown(); - aContext.ungetService(launcherRef); - } - stopper = new BundleStopper(context); - stopper.stopBundles(); - } - - private boolean isFatalException(Throwable error) { - if (error instanceof VirtualMachineError) { - return true; - } - if (error instanceof ThreadDeath) { - return true; - } - return false; - } - - public void handleRuntimeError(Throwable error) { - try { - // check the prop each time this happens (should NEVER happen!) - exitOnError = Boolean.valueOf(FrameworkProperties.getProperty(PROP_EXITONERROR, "true")).booleanValue(); //$NON-NLS-1$ - String message = EclipseAdaptorMsg.ECLIPSE_ADAPTOR_RUNTIME_ERROR; - if (exitOnError && isFatalException(error)) - message += ' ' + EclipseAdaptorMsg.ECLIPSE_ADAPTOR_EXITING; - FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, error, null); - getFrameworkLog().log(logEntry); - } catch (Throwable t) { - // we may be in a currupted state and must be able to handle any - // errors (ie OutOfMemoryError) - // that may occur when handling the first error; this is REALLY the - // last resort. - try { - error.printStackTrace(); - t.printStackTrace(); - } catch (Throwable t1) { - // if we fail that then we are beyond help. - } - } finally { - // do the exit outside the try block just incase another runtime - // error was thrown while logging - if (exitOnError && isFatalException(error)) - System.exit(13); - } - } - - protected void setLog(FrameworkLog log) { - frameworkLog = log; - } - - BundleStopper getBundleStopper() { - return stopper; - } - - private StorageManager initStorageManager(File baseDir, String lockMode, boolean readOnly) { - StorageManager manager = new StorageManager(baseDir, lockMode, readOnly); - try { - manager.open(!readOnly); - } catch (IOException ex) { - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Error reading framework metadata: " + ex.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(ex); - } - String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FILEMANAGER_OPEN_ERROR, ex.getMessage()); - FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, ex, null); - getFrameworkLog().log(logEntry); - } - return manager; - } - - protected void updateState(BundleData bundleData, int type) throws BundleException { - super.updateState(bundleData, type); - requestSave(); - } - - private void requestSave() { - // Only when the State saver is enabled will the stateSaver be started. - if (stateSaver == null) - return; - if (stateManager != null) - stateSaver.requestSave(); - } - - private class StateSaver implements Runnable { - private long delay_interval = 30000; // 30 seconds. - private long max_total_delay_interval = 1800000; // 30 minutes. - private boolean shutdown = false; - private long lastSaveTime = 0; - private Thread runningThread = null; - - StateSaver() { - String prop = FrameworkProperties.getProperty("eclipse.stateSaveDelayInterval"); //$NON-NLS-1$ - if (prop != null) { - try { - long val = Long.parseLong(prop); - if (val >= 1000 && val <= 1800000) { - delay_interval = val; - max_total_delay_interval = val * 60; - } - } catch (NumberFormatException e) { - // ignore - } - } - } - - public void run() { - State systemState = getState(); - synchronized (systemState) { - long firstSaveTime = lastSaveTime; - long curSaveTime = 0; - long delayTime; - do { - do { - if ((System.currentTimeMillis() - firstSaveTime) > max_total_delay_interval) - // Waiting time has been too long, so break to start saving State data to file. - break; - delayTime = Math.min(delay_interval, lastSaveTime - curSaveTime); - curSaveTime = lastSaveTime; - // wait for other save requests - try { - if (!shutdown) - systemState.wait(delayTime); - } catch (InterruptedException ie) { - // force break from do/while loops - curSaveTime = lastSaveTime; - break; - } - - // Continue the loop if 'lastSaveTime' is increased again during waiting. - } while (!shutdown && curSaveTime < lastSaveTime); - // Save State and Meta data. - saveStateToFile(false); - saveMetaData(); - // Continue the loop if Saver is asked again during saving State data to file. - } while (!shutdown && curSaveTime < lastSaveTime); - runningThread = null; // clear runningThread - } - } - - void shutdown() { - State systemState = getState(); - Thread joinWith = null; - synchronized (systemState) { - shutdown = true; - joinWith = runningThread; - systemState.notifyAll(); // To wakeup sleeping thread. - } - try { - if (joinWith != null) - // There should be no deadlock when 'shutdown' is true. - joinWith.join(); - } catch (InterruptedException ie){ - if (Debug.DEBUG && Debug.DEBUG_GENERAL) { - Debug.println("Error shutdowning StateSaver: " + ie.getMessage()); //$NON-NLS-1$ - Debug.printStackTrace(ie); - } - } - } - - void requestSave() { - State systemState = getState(); - synchronized (systemState) { - lastSaveTime = System.currentTimeMillis(); - if (runningThread == null) { - runningThread = new Thread(this, "State Saver"); //$NON-NLS-1$ - runningThread.start(); - } - } - } - } -} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseBundleData.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseBundleData.java deleted file mode 100644 index dd797787a..000000000 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseBundleData.java +++ /dev/null @@ -1,575 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2006 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.core.runtime.adaptor; - -import java.io.*; -import java.net.URL; -import java.util.*; -import org.eclipse.core.runtime.internal.adaptor.*; -import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; -import org.eclipse.osgi.framework.adaptor.core.*; -import org.eclipse.osgi.framework.internal.core.Constants; -import org.eclipse.osgi.framework.internal.core.FrameworkProperties; -import org.eclipse.osgi.framework.log.FrameworkLogEntry; -import org.eclipse.osgi.framework.util.Headers; -import org.eclipse.osgi.service.datalocation.Location; -import org.eclipse.osgi.service.pluginconversion.PluginConversionException; -import org.eclipse.osgi.util.ManifestElement; -import org.eclipse.osgi.util.NLS; -import org.osgi.framework.BundleException; -import org.osgi.framework.Version; - -/** - * The BundleData implementation used Eclipse. - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -//Maybe for consistency should it be overriden to do nothing. See also EclipseAdaptor.saveMetadataFor(BundleData) -public class EclipseBundleData extends AbstractBundleData { - /** bundle manifest type unknown */ - static public final byte MANIFEST_TYPE_UNKNOWN = PluginConverterImpl.MANIFEST_TYPE_UNKNOWN; - /** bundle manifest type bundle (META-INF/MANIFEST.MF) */ - static public final byte MANIFEST_TYPE_BUNDLE = PluginConverterImpl.MANIFEST_TYPE_BUNDLE; - /** bundle manifest type plugin (plugin.xml) */ - static public final byte MANIFEST_TYPE_PLUGIN = PluginConverterImpl.MANIFEST_TYPE_PLUGIN; - /** bundle manifest type fragment (fragment.xml) */ - static public final byte MANIFEST_TYPE_FRAGMENT = PluginConverterImpl.MANIFEST_TYPE_FRAGMENT; - /** bundle manifest type jared bundle */ - static public final byte MANIFEST_TYPE_JAR = PluginConverterImpl.MANIFEST_TYPE_JAR; - - private static String[] libraryVariants = null; - - /** data to detect modification made in the manifest */ - private long manifestTimeStamp = 0; - private byte manifestType = MANIFEST_TYPE_UNKNOWN; - - // URL protocol designations - /** The platform protocol */ - public static final String PROTOCOL = "platform"; //$NON-NLS-1$ - /** The file protocol */ - public static final String FILE = "file"; //$NON-NLS-1$ - - private static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$ - /** the Plugin-Class header */ - protected String pluginClass = null; - /** Eclipse-AutoStart header */ - private boolean autoStart; - private String[] autoStartExceptions; - /** shortcut to know if a bundle has a buddy */ - protected String buddyList; - /** shortcut to know if a bundle is a registrant to a registered policy */ - protected String registeredBuddyList; - /** shortcut to know if the bundle manifest has package info */ - protected boolean hasPackageInfo; - /** marks the data as dirty */ - protected boolean dirty = false; - - private static String[] buildLibraryVariants() { - ArrayList result = new ArrayList(); - EclipseEnvironmentInfo info = EclipseEnvironmentInfo.getDefault(); - result.add("ws/" + info.getWS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ - result.add("os/" + info.getOS() + "/" + info.getOSArch() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - result.add("os/" + info.getOS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ - String nl = info.getNL(); - nl = nl.replace('_', '/'); - while (nl.length() > 0) { - result.add("nl/" + nl + "/"); //$NON-NLS-1$ //$NON-NLS-2$ - int i = nl.lastIndexOf('/'); - nl = (i < 0) ? "" : nl.substring(0, i); //$NON-NLS-1$ - } - result.add(""); //$NON-NLS-1$ - return (String[]) result.toArray(new String[result.size()]); - } - - /** - * Constructor for EclipseBundleData. - * @param adaptor The adaptor for this bundle data - * @param id The bundle id for this bundle data - */ - public EclipseBundleData(AbstractFrameworkAdaptor adaptor, long id) { - super(adaptor, id); - } - - /** - * Initialize an existing bundle - * @throws IOException if any error occurs loading the existing bundle - */ - public void initializeExistingBundle() throws IOException { - createBaseBundleFile(); - if (!checkManifestTimeStamp()) { - if (getBundleStoreDir().exists()) { - /* create .delete */ - FileOutputStream out = new FileOutputStream(new File(getBundleStoreDir(), ".delete")); - out.close(); - } - throw new IOException(); - } - } - - private boolean checkManifestTimeStamp() { - if (!"true".equalsIgnoreCase(FrameworkProperties.getProperty(PROP_CHECK_CONFIG))) //$NON-NLS-1$ - return true; - - if (PluginConverterImpl.getTimeStamp(getBaseFile(), getManifestType()) == getManifestTimeStamp()) { - if ((getManifestType() & (MANIFEST_TYPE_JAR | MANIFEST_TYPE_BUNDLE)) != 0) - return true; - String cacheLocation = FrameworkProperties.getProperty(LocationManager.PROP_MANIFEST_CACHE); - Location parentConfiguration = LocationManager.getConfigurationLocation().getParentLocation(); - if (parentConfiguration != null) { - try { - return checkManifestAndParent(cacheLocation, getSymbolicName(), getVersion().toString(), getManifestType()) != null; - } catch (BundleException e) { - return false; - } - } - File cacheFile = new File(cacheLocation, getSymbolicName() + '_' + getVersion() + ".MF"); //$NON-NLS-1$ - if (cacheFile.isFile()) - return true; - } - return false; - } - - /** - * Returns the absolute path name of a native library. The VM invokes this - * method to locate the native libraries that belong to classes loaded with - * this class loader. If this method returns <code>null</code>, the VM - * searches the library along the path specified as the <code>java.library.path</code> - * property. - * - * @param libName - * the library name - * @return the absolute path of the native library - */ - public String findLibrary(String libName) { - // first do the standard OSGi lookup using the native clauses - // in the manifest. If that fails, do the legacy Eclipse lookup. - String result = super.findLibrary(libName); - if (result != null) - return result; - if (libraryVariants == null) - libraryVariants = buildLibraryVariants(); - if (libName.length() == 0) - return null; - if (libName.charAt(0) == '/' || libName.charAt(0) == '\\') - libName = libName.substring(1); - libName = System.mapLibraryName(libName); - - // if (DEBUG && DEBUG_SHOW_ACTIONS && debugNative(libName)) - // debug("findLibrary(" + libName + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - - return searchVariants(libraryVariants, libName); - - } - - private String searchVariants(String[] variants, String path) { - for (int i = 0; i < variants.length; i++) { - BundleEntry libEntry = baseBundleFile.getEntry(variants[i] + path); - if (libEntry == null) { - // if (DEBUG && DEBUG_SHOW_FAILURE) - // debug("not found " + variants[i] + path); - // //$NON-NLS-1$ - } else { - // if (DEBUG && DEBUG_SHOW_SUCCESS) - // debug("found " + path + " as " + - // variants[i] + path); //$NON-NLS-1$ //$NON-NLS-2$ - File libFile = baseBundleFile.getFile(variants[i] + path); - if (libFile == null) - return null; - // see bug 88697 - HP requires libraries to have executable permissions - if (org.eclipse.osgi.service.environment.Constants.OS_HPUX.equals(EclipseEnvironmentInfo.getDefault().getOS())) { - try { - // use the string array method in case there is a space in the path - Runtime.getRuntime().exec(new String[] {"chmod", "755", libFile.getAbsolutePath()}).waitFor(); //$NON-NLS-1$ //$NON-NLS-2$ - } catch (Exception e) { - e.printStackTrace(); - } - } - return libFile.getAbsolutePath(); - } - } - return null; - } - - //TODO Unused method - private URL[] getSearchURLs(URL target) { - return new URL[] {target}; - } - - public synchronized Dictionary getManifest() throws BundleException { - return getManifest(false); - } - - /** - * Gets the manifest for this bundle. If this is the first time the manifest is - * ever accessed then the manifest is loaded from the manifest file in the bundle; - * otherwise the manifest is loaded from cached data. - * @param first set to true if this is the first time the manifest is accessed - * for this bundle - * @return the manifest for this bundle - * @throws BundleException if any error occurs loading the manifest - */ - public synchronized Dictionary getManifest(boolean first) throws BundleException { - if (manifest == null) - manifest = first ? loadManifest() : new CachedManifest(this); - return manifest; - } - - private boolean isComplete(Dictionary manifest) { - // a manifest is complete if it has a Bundle-SymbolicName entry... - if (manifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME) != null) - return true; - // ...or it does not have a plugin/fragment manifest where to get the other entries from - return getEntry(PluginConverterImpl.PLUGIN_MANIFEST) == null && getEntry(PluginConverterImpl.FRAGMENT_MANIFEST) == null; - } - - /** - * Loads the bundle manifest from the bundle. - * @return the bundle manifest - * @throws BundleException if an error occurs loading the bundle manifest - */ - public synchronized Dictionary loadManifest() throws BundleException { - URL url = getEntry(Constants.OSGI_BUNDLE_MANIFEST); - if (url != null) { - // the bundle has a built-in manifest - we may not have to generate one - Dictionary builtIn = loadManifestFrom(url); - // if the manifest is not complete, add entries derived from plug-in/fragment manifest - if (!isComplete(builtIn)) { - Dictionary generatedManifest = generateManifest(builtIn); - if (generatedManifest != null) - return generatedManifest; - } - // the manifest is complete or we could not complete it - take it as it is - manifestType = MANIFEST_TYPE_BUNDLE; - if (getBaseFile().isFile()) { - manifestTimeStamp = getBaseFile().lastModified(); - manifestType |= MANIFEST_TYPE_JAR; - } else - manifestTimeStamp = getBaseBundleFile().getEntry(Constants.OSGI_BUNDLE_MANIFEST).getTime(); - return builtIn; - } - Dictionary result = generateManifest(null); - if (result == null) - throw new BundleException(NLS.bind(EclipseAdaptorMsg.ECLIPSE_DATA_MANIFEST_NOT_FOUND, getLocation())); - return result; - } - - private Headers basicCheckManifest(String cacheLocation, String symbolicName, String version, byte inputType) throws BundleException { - File currentFile = new File(cacheLocation, symbolicName + '_' + version + ".MF"); //$NON-NLS-1$ - if (PluginConverterImpl.upToDate(currentFile, getBaseFile(), inputType)) { - try { - return Headers.parseManifest(new FileInputStream(currentFile)); - } catch (FileNotFoundException e) { - // do nothing. - } - } - return null; - } - - private Headers checkManifestAndParent(String cacheLocation, String symbolicName, String version, byte inputType) throws BundleException { - Headers result = basicCheckManifest(cacheLocation, symbolicName, version, inputType); - if (result != null) - return result; - - Location parentConfiguration = null; - if ((parentConfiguration = LocationManager.getConfigurationLocation().getParentLocation()) != null) { - result = basicCheckManifest(new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + '/' + LocationManager.MANIFESTS_DIR).toString(), symbolicName, version, inputType); - } - return result; - } - - private Dictionary generateManifest(Dictionary originalManifest) throws BundleException { - String cacheLocation = FrameworkProperties.getProperty(LocationManager.PROP_MANIFEST_CACHE); - if (getSymbolicName() != null) { - Headers existingHeaders = checkManifestAndParent(cacheLocation, getSymbolicName(), getVersion().toString(), manifestType); - if (existingHeaders != null) - return existingHeaders; - } - - PluginConverterImpl converter = PluginConverterImpl.getDefault(); - - Dictionary generatedManifest; - try { - generatedManifest = converter.convertManifest(getBaseFile(), true, null, true, null); - } catch (PluginConversionException pce) { - String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CONVERTER_ERROR_CONVERTING, getBaseFile()); - throw new BundleException(message, pce); - } - - //Now we know the symbolicId and the version of the bundle, we check to see if don't have a manifest for it already - Version version = Version.parseVersion((String) generatedManifest.get(Constants.BUNDLE_VERSION)); - String symbolicName = ManifestElement.parseHeader(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME, (String) generatedManifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME))[0].getValue(); - ManifestElement generatedFrom = ManifestElement.parseHeader(PluginConverterImpl.GENERATED_FROM, (String) generatedManifest.get(PluginConverterImpl.GENERATED_FROM))[0]; - Headers existingHeaders = checkManifestAndParent(cacheLocation, symbolicName, version.toString(), Byte.parseByte(generatedFrom.getAttribute(PluginConverterImpl.MANIFEST_TYPE_ATTRIBUTE))); - //We don't have a manifest. - setManifestTimeStamp(Long.parseLong(generatedFrom.getValue())); - setManifestType(Byte.parseByte(generatedFrom.getAttribute(PluginConverterImpl.MANIFEST_TYPE_ATTRIBUTE))); - if (!adaptor.canWrite() || existingHeaders != null) - return existingHeaders; - - //merge the original manifest with the generated one - if (originalManifest != null) { - Enumeration keysEnum = originalManifest.keys(); - while (keysEnum.hasMoreElements()) { - Object key = keysEnum.nextElement(); - generatedManifest.put(key, originalManifest.get(key)); - } - } - - //write the generated manifest - File bundleManifestLocation = new File(cacheLocation, symbolicName + '_' + version.toString() + ".MF"); //$NON-NLS-1$ - try { - converter.writeManifest(bundleManifestLocation, generatedManifest, true); - } catch (Exception e) { - //TODO Need to log - } - return generatedManifest; - - } - - private Dictionary loadManifestFrom(URL manifestURL) throws BundleException { - try { - return Headers.parseManifest(manifestURL.openStream()); - } catch (IOException e) { - throw new BundleException(NLS.bind(EclipseAdaptorMsg.ECLIPSE_DATA_ERROR_READING_MANIFEST, getLocation()), e); - } - } - - protected void loadFromManifest() throws BundleException { - getManifest(true); - super.loadFromManifest(); - // manifest cannot ever be a cached one otherwise the lines below are bogus - if (manifest instanceof CachedManifest) - throw new IllegalStateException(); - pluginClass = (String) manifest.get(EclipseAdaptor.PLUGIN_CLASS); - String lazyStart = (String) manifest.get(EclipseAdaptor.ECLIPSE_LAZYSTART); - if (lazyStart == null) - lazyStart = (String) manifest.get(EclipseAdaptor.ECLIPSE_AUTOSTART); - parseAutoStart(lazyStart); - buddyList = (String) manifest.get(Constants.BUDDY_LOADER); - registeredBuddyList = (String) manifest.get(Constants.REGISTERED_POLICY); - hasPackageInfo = hasPackageInfo(getEntry(Constants.OSGI_BUNDLE_MANIFEST)); - } - - // Used to check the bundle manifest file for any package information. - // This is used when '.' is on the Bundle-ClassPath to prevent reading - // the bundle manifest for pacakge information when loading classes. - private boolean hasPackageInfo(URL url) { - if (url == null) - return false; - BufferedReader br = null; - try { - br = new BufferedReader(new InputStreamReader(url.openStream())); - String line; - while ((line = br.readLine()) != null) { - if (line.startsWith("Specification-Title: ") || line.startsWith("Specification-Version: ") || line.startsWith("Specification-Vendor: ") || line.startsWith("Implementation-Title: ") || line.startsWith("Implementation-Version: ") || line.startsWith("Implementation-Vendor: ")) //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ - return true; - } - } catch (IOException ioe) { - // do nothing - } finally { - if (br != null) - try { - br.close(); - } catch (IOException e) { - // do nothing - } - } - return false; - } - - /** - * Returns the plugin class - * @return the plugin class - */ - public String getPluginClass() { - return pluginClass; - } - - /** - * Returns the buddy list for this bundle - * @return the buddy list for this bundle - */ - public String getBuddyList() { - return buddyList; - } - - /** - * Returns the registered buddy list for this bundle - * @return the registered buddy list for this bundle - */ - public String getRegisteredBuddyList() { - return registeredBuddyList; - } - - /** - * Sets the plugin class - * @param value the plugin class - */ - public void setPluginClass(String value) { - pluginClass = value; - } - - /** - * Returns the timestamp for the manifest file - * @return the timestamp for the manifest file - */ - public long getManifestTimeStamp() { - return manifestTimeStamp; - } - - /** - * Sets the manifest timestamp for this bundle - * @param stamp the manifest timestamp - */ - public void setManifestTimeStamp(long stamp) { - manifestTimeStamp = stamp; - } - - /** - * Returns the manifest type - * @return the manifest type - */ - public byte getManifestType() { - return manifestType; - } - - /** - * Sets the manifest type - * @param manifestType the manifest type - */ - public void setManifestType(byte manifestType) { - this.manifestType = manifestType; - } - - /** - * Sets the auto start flag - * @param value the auto start flag - */ - public void setAutoStart(boolean value) { - autoStart = value; - } - - /** - * Checks whether this bundle is auto started for all resource/class loads - * @return true if the bundle is auto started; false otherwise - */ - public boolean isAutoStart() { - return autoStart; - } - - /** - * Returns the status of this bundle which is persisted on shutdown. For bundles - * which are auto started the started state is removed to prevent the bundle from - * being started on the next startup. - * @return the status of this bundle which is persisted on shutdown - */ - public int getPersistentStatus() { - // omit the active state if necessary - return isAutoStartable() ? (~Constants.BUNDLE_STARTED) & getStatus() : getStatus(); - } - - /** - * Sets the list of auto start exceptions for this bundle - * @param autoStartExceptions the list of auto start exceptions - */ - public void setAutoStartExceptions(String[] autoStartExceptions) { - this.autoStartExceptions = autoStartExceptions; - } - - /** - * Returns the auto start exception packages - * @return the auto start exception packages - */ - public String[] getAutoStartExceptions() { - return autoStartExceptions; - } - - private void parseAutoStart(String headerValue) { - autoStart = false; - autoStartExceptions = null; - ManifestElement[] allElements = null; - try { - allElements = ManifestElement.parseHeader(EclipseAdaptor.ECLIPSE_LAZYSTART, headerValue); - } catch (BundleException e) { - // just use the default settings (no auto activation) - String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_CANNOT_GET_HEADERS, getLocation()); - EclipseAdaptor.getDefault().getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null)); - } - //Eclipse-AutoStart not found... - if (allElements == null) - return; - // the single value for this element should be true|false - autoStart = "true".equalsIgnoreCase(allElements[0].getValue()); //$NON-NLS-1$ - // look for any exceptions (the attribute) to the autoActivate setting - String exceptionsValue = allElements[0].getAttribute(EclipseAdaptor.ECLIPSE_LAZYSTART_EXCEPTIONS); - if (exceptionsValue == null) - return; - StringTokenizer tokenizer = new StringTokenizer(exceptionsValue, ","); //$NON-NLS-1$ - int numberOfTokens = tokenizer.countTokens(); - autoStartExceptions = new String[numberOfTokens]; - for (int i = 0; i < numberOfTokens; i++) - autoStartExceptions[i] = tokenizer.nextToken().trim(); - } - - /** - * Checks whether this bundle is auto started for all resource/class loads or only for a - * subset of resource/classloads - * @return true if the bundle is auto started; false otherwise - */ - public boolean isAutoStartable() { - return autoStart || (autoStartExceptions != null && autoStartExceptions.length > 0); - } - - /** - * Save the bundle data in the data file. - * - * @throws IOException if a write error occurs. - */ - public synchronized void save() throws IOException { - if (adaptor.canWrite() && isDirty()) { - ((EclipseAdaptor) adaptor).saveMetaDataFor(this); - this.dirty = false; - } - } - - public String toString() { - return "BundleData for " + getSymbolicName() + " (" + id + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - public File getParentGenerationDir() { - Location parentConfiguration = null; - Location currentConfiguration = LocationManager.getConfigurationLocation(); - if (currentConfiguration != null && (parentConfiguration = currentConfiguration.getParentLocation()) != null) - return new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + '/' + LocationManager.BUNDLES_DIR + '/' + getBundleID() + '/' + getGeneration()); - return null; - } - - public void setStartLevel(int startLevel) { - super.setStartLevel(startLevel); - dirty = true; - } - - public void setStatus(int status) { - super.setStatus(status); - if (!isAutoStartable()) - dirty = true; - } - - public boolean isDirty() { - return dirty; - } - - void setDirty (boolean dirty) { - this.dirty = dirty; - } -} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseClassLoader.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseClassLoader.java deleted file mode 100644 index 07f120434..000000000 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseClassLoader.java +++ /dev/null @@ -1,407 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2006 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.core.runtime.adaptor; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.security.ProtectionDomain; -import java.util.ArrayList; -import java.util.StringTokenizer; -import java.util.jar.Attributes; -import java.util.jar.Manifest; -import org.eclipse.core.runtime.internal.adaptor.BundleStopper; -import org.eclipse.core.runtime.internal.adaptor.EclipseEnvironmentInfo; -import org.eclipse.core.runtime.internal.stats.*; -import org.eclipse.osgi.framework.adaptor.*; -import org.eclipse.osgi.framework.adaptor.core.*; -import org.eclipse.osgi.framework.internal.core.AbstractBundle; -import org.eclipse.osgi.framework.internal.core.FrameworkProperties; -import org.eclipse.osgi.framework.internal.core.Msg; -import org.eclipse.osgi.framework.log.FrameworkLogEntry; -import org.eclipse.osgi.util.NLS; -import org.osgi.framework.*; - -/** - * Implements the class loader for Eclipse - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -public class EclipseClassLoader extends DefaultClassLoader { - private static String[] NL_JAR_VARIANTS = buildNLJarVariants(EclipseEnvironmentInfo.getDefault().getNL()); - private static boolean DEFINE_PACKAGES; - private static final String VARIABLE_DELIM_STRING = "$"; //$NON-NLS-1$ - private static final char VARIABLE_DELIM_CHAR = '$'; - private static final String EXTERNAL_LIB_PREFIX = "external:"; //$NON-NLS-1$ - static { - try { - Class.forName("java.lang.Package"); //$NON-NLS-1$ - DEFINE_PACKAGES = true; - } catch (ClassNotFoundException e) { - DEFINE_PACKAGES = false; - } - } - - public EclipseClassLoader(ClassLoaderDelegate delegate, ProtectionDomain domain, String[] classpath, ClassLoader parent, BundleData bundleData) { - super(delegate, domain, classpath, parent, (EclipseBundleData) bundleData); - } - - public Class findLocalClass(String className) throws ClassNotFoundException { - if (StatsManager.MONITOR_CLASSES) //Suport for performance analysis - ClassloaderStats.startLoadingClass(getClassloaderId(), className); - boolean found = true; - - try { - AbstractBundle bundle = (AbstractBundle) hostdata.getBundle(); - // If the bundle is active, uninstalled or stopping then the bundle has already - // been initialized (though it may have been destroyed) so just return the class. - if ((bundle.getState() & (Bundle.ACTIVE | Bundle.UNINSTALLED | Bundle.STOPPING)) != 0) - return basicFindLocalClass(className); - - // The bundle is not active and does not require activation, just return the class - if (!shouldActivateFor(className)) - return basicFindLocalClass(className); - - // The bundle is starting. Note that if the state changed between the tests - // above and this test (e.g., it was not ACTIVE but now is), that's ok, we will - // just try to start it again (else case). - // TODO need an explanation here of why we duplicated the mechanism - // from the framework rather than just calling start() and letting it sort it out. - if (bundle.getState() == Bundle.STARTING) { - // If the thread trying to load the class is the one trying to activate the bundle, then return the class - if (bundle.testStateChanging(Thread.currentThread()) || bundle.testStateChanging(null)) - return basicFindLocalClass(className); - - // If it's another thread, we wait and try again. In any case the class is returned. - // The difference is that an exception can be logged. - // TODO do we really need this test? We just did it on the previous line? - if (!bundle.testStateChanging(Thread.currentThread())) { - Thread threadChangingState = bundle.getStateChanging(); - if (StatsManager.TRACE_BUNDLES && threadChangingState != null) { - System.out.println("Concurrent startup of bundle " + bundle.getSymbolicName() + " by " + Thread.currentThread() + " and " + threadChangingState.getName() + ". Waiting up to 5000ms for " + threadChangingState + " to finish the initialization."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ - } - long start = System.currentTimeMillis(); - long delay = 5000; - long timeLeft = delay; - while (true) { - try { - Thread.sleep(100); // do not release the classloader lock (bug 86713) - if (bundle.testStateChanging(null) || timeLeft <= 0) - break; - } catch (InterruptedException e) { - //Ignore and keep waiting - } - timeLeft = start + delay - System.currentTimeMillis(); - } - if (timeLeft <= 0 || bundle.getState() != Bundle.ACTIVE) { - String bundleName = bundle.getSymbolicName() == null ? Long.toString(bundle.getBundleId()) : bundle.getSymbolicName(); - String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_CONCURRENT_STARTUP, new Object[] {Thread.currentThread().getName(), className, threadChangingState.getName(), bundleName, Long.toString(delay)}); - EclipseAdaptor.getDefault().getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, new Exception(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_GENERATED_EXCEPTION), null)); - } - return basicFindLocalClass(className); - } - } - - //The bundle must be started. - try { - hostdata.getBundle().start(); - } catch (BundleException e) { - String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_ACTIVATION, bundle.getSymbolicName(), Long.toString(bundle.getBundleId())); - EclipseAdaptor.getDefault().getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null)); - throw new ClassNotFoundException(className, e); - } - return basicFindLocalClass(className); - } catch (ClassNotFoundException e) { - found = false; - throw e; - } finally { - if (StatsManager.MONITOR_CLASSES) - ClassloaderStats.endLoadingClass(getClassloaderId(), className, found); - } - } - - /** - * Do the basic work for finding a class. This avoids the activation detection etc - * and can be used by subclasses to override the default (from the superclass) - * way of finding classes. - * @param name the class to look for - * @return the found class - * @throws ClassNotFoundException if the requested class cannot be found - */ - protected Class basicFindLocalClass(String name) throws ClassNotFoundException { - return super.findLocalClass(name); - } - - /** - * Determines if for loading the given class we should activate the bundle. - */ - private boolean shouldActivateFor(String className) throws ClassNotFoundException { - if (!isAutoStartable(className)) - return false; - //Don't reactivate on shut down - if (hostdata.getAdaptor().isStopping()) { - BundleStopper stopper = EclipseAdaptor.getDefault().getBundleStopper(); - if (stopper != null && stopper.isStopped(hostdata.getBundle())) { - String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_ALREADY_STOPPED, className, hostdata.getSymbolicName()); - throw new ClassNotFoundException(message); - } - } - return true; - } - - private boolean isAutoStartable(String className) { - boolean autoStart = ((EclipseBundleData) hostdata).isAutoStart(); - String[] autoStartExceptions = ((EclipseBundleData) hostdata).getAutoStartExceptions(); - // no exceptions, it is easy to figure it out - if (autoStartExceptions == null) - return autoStart; - // otherwise, we need to check if the package is in the exceptions list - int dotPosition = className.lastIndexOf('.'); - // the class has no package name... no exceptions apply - if (dotPosition == -1) - return autoStart; - String packageName = className.substring(0, dotPosition); - // should activate if autoStart and package is not an exception, or if !autoStart and package is exception - return autoStart ^ contains(autoStartExceptions, packageName); - } - - private boolean contains(String[] array, String element) { - for (int i = 0; i < array.length; i++) - if (array[i].equals(element)) - return true; - return false; - } - - /** - * Override defineClass to allow for package defining. - */ - protected Class defineClass(String name, byte[] classbytes, int off, int len, ClasspathEntry classpathEntry) throws ClassFormatError { - if (!DEFINE_PACKAGES) - return super.defineClass(name, classbytes, off, len, classpathEntry); - - // Define the package if it is not the default package. - int lastIndex = name.lastIndexOf('.'); - if (lastIndex != -1) { - String packageName = name.substring(0, lastIndex); - Package pkg = getPackage(packageName); - if (pkg == null) { - // get info about the package from the classpath entry's manifest. - String specTitle = null, specVersion = null, specVendor = null, implTitle = null, implVersion = null, implVendor = null; - Manifest mf = ((EclipseClasspathEntry) classpathEntry).getManifest(); - if (mf != null) { - Attributes mainAttributes = mf.getMainAttributes(); - String dirName = packageName.replace('.', '/') + '/'; - Attributes packageAttributes = mf.getAttributes(dirName); - boolean noEntry = false; - if (packageAttributes == null) { - noEntry = true; - packageAttributes = mainAttributes; - } - specTitle = packageAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE); - if (specTitle == null && !noEntry) - specTitle = mainAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE); - specVersion = packageAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION); - if (specVersion == null && !noEntry) - specVersion = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION); - specVendor = packageAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR); - if (specVendor == null && !noEntry) - specVendor = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR); - implTitle = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE); - if (implTitle == null && !noEntry) - implTitle = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE); - implVersion = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION); - if (implVersion == null && !noEntry) - implVersion = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION); - implVendor = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); - if (implVendor == null && !noEntry) - implVendor = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); - } - // The package is not defined yet define it before we define the class. - // TODO still need to seal packages. - definePackage(packageName, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, null); - } - } - return super.defineClass(name, classbytes, off, len, classpathEntry); - } - - private String getClassloaderId() { - return hostdata.getBundle().getSymbolicName(); - } - - public URL getResource(String name) { - URL result = super.getResource(name); - if (StatsManager.MONITOR_RESOURCES) { - if (result != null && name.endsWith(".properties")) { //$NON-NLS-1$ - ClassloaderStats.loadedBundle(getClassloaderId(), new ResourceBundleStats(getClassloaderId(), name, result)); - } - } - return result; - } - - protected void findClassPathEntry(ArrayList result, String entry, AbstractBundleData bundledata, ProtectionDomain domain) { - String var = hasPrefix(entry); - if (var != null) { - // find internal library using eclipse predefined vars - findInternalClassPath(var, result, entry, bundledata, domain); - return; - } - if (entry.startsWith(EXTERNAL_LIB_PREFIX)) { - entry = entry.substring(EXTERNAL_LIB_PREFIX.length()); - // find external library using system property substitution - ClasspathEntry cpEntry = getExternalClassPath(substituteVars(entry), bundledata, domain); - if (cpEntry != null) - result.add(cpEntry); - return; - } - // if we get here just do the default searching - super.findClassPathEntry(result, entry, bundledata, domain); - } - - private void findInternalClassPath(String var, ArrayList result, String entry, AbstractBundleData bundledata, ProtectionDomain domain) { - if (var.equals("ws")) { //$NON-NLS-1$ - super.findClassPathEntry(result, "ws/" + EclipseEnvironmentInfo.getDefault().getWS() + entry.substring(4), bundledata, domain); //$NON-NLS-1$ - return; - } - if (var.equals("os")) { //$NON-NLS-1$ - super.findClassPathEntry(result, "os/" + EclipseEnvironmentInfo.getDefault().getOS() + entry.substring(4), bundledata, domain); //$NON-NLS-1$ - return; - } - if (var.equals("nl")) { //$NON-NLS-1$ - entry = entry.substring(4); - for (int i = 0; i < NL_JAR_VARIANTS.length; i++) { - if (addClassPathEntry(result, "nl/" + NL_JAR_VARIANTS[i] + entry, bundledata, domain)) //$NON-NLS-1$ - return; - } - // is we are not in development mode, post some framework errors. - if (!DevClassPathHelper.inDevelopmentMode()) { - //BundleException be = new BundleException(Msg.formatter.getString("BUNDLE_CLASSPATH_ENTRY_NOT_FOUND_EXCEPTION", entry, hostdata.getLocation())); //$NON-NLS-1$ - BundleException be = new BundleException(NLS.bind(Msg.BUNDLE_CLASSPATH_ENTRY_NOT_FOUND_EXCEPTION, entry)); - bundledata.getAdaptor().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, bundledata.getBundle(), be); - } - } - } - - private static String[] buildNLJarVariants(String nl) { - ArrayList result = new ArrayList(); - nl = nl.replace('_', '/'); - while (nl.length() > 0) { - result.add("nl/" + nl + "/"); //$NON-NLS-1$ //$NON-NLS-2$ - int i = nl.lastIndexOf('/'); - nl = (i < 0) ? "" : nl.substring(0, i); //$NON-NLS-1$ - } - result.add(""); //$NON-NLS-1$ - return (String[]) result.toArray(new String[result.size()]); - } - - //return a String representing the string found between the $s - private String hasPrefix(String libPath) { - if (libPath.startsWith("$ws$")) //$NON-NLS-1$ - return "ws"; //$NON-NLS-1$ - if (libPath.startsWith("$os$")) //$NON-NLS-1$ - return "os"; //$NON-NLS-1$ - if (libPath.startsWith("$nl$")) //$NON-NLS-1$ - return "nl"; //$NON-NLS-1$ - return null; - } - - private String substituteVars(String cp) { - StringBuffer buf = new StringBuffer(cp.length()); - StringTokenizer st = new StringTokenizer(cp, VARIABLE_DELIM_STRING, true); - boolean varStarted = false; // indicates we are processing a var subtitute - String var = null; // the current var key - while (st.hasMoreElements()) { - String tok = st.nextToken(); - if (VARIABLE_DELIM_STRING.equals(tok)) { - if (!varStarted) { - varStarted = true; // we found the start of a var - var = ""; //$NON-NLS-1$ - } else { - // we have found the end of a var - String prop = null; - // get the value of the var from FrameworkProperties - if (var != null && var.length() > 0) - prop = FrameworkProperties.getProperty(var); - if (prop != null) - // found a value; use it - buf.append(prop); - else - // could not find a value append the var name w/o delims - buf.append(var == null ? "" : var); //$NON-NLS-1$ - varStarted = false; - var = null; - } - } else { - if (!varStarted) - buf.append(tok); // the token is not part of a var - else - var = tok; // the token is the var key; save the key to process when we find the end token - } - } - if (var != null) - // found a case of $var at the end of the cp with no trailing $; just append it as is. - buf.append(VARIABLE_DELIM_CHAR).append(var); - return buf.toString(); - } - - /** - * Override to create EclipseClasspathEntry objects. EclipseClasspathEntry - * allows access to the manifest file for the classpath entry. - */ - protected ClasspathEntry createClassPathEntry(BundleFile bundlefile, ProtectionDomain domain) { - return new EclipseClasspathEntry(bundlefile, domain); - } - - /** - * A ClasspathEntry that has a manifest associated with it. - */ - protected class EclipseClasspathEntry extends ClasspathEntry { - Manifest mf; - boolean initMF = false; - - protected EclipseClasspathEntry(BundleFile bundlefile, ProtectionDomain domain) { - super(bundlefile, domain); - } - - public Manifest getManifest() { - if (initMF) - return mf; - if (!hasPackageInfo()) { - initMF = true; - mf = null; - return mf; - } - BundleEntry mfEntry = getBundleFile().getEntry(org.eclipse.osgi.framework.internal.core.Constants.OSGI_BUNDLE_MANIFEST); - if (mfEntry != null) - try { - InputStream manIn = mfEntry.getInputStream(); - mf = new Manifest(manIn); - manIn.close(); - } catch (IOException e) { - // do nothing - } - initMF = true; - return mf; - } - - private boolean hasPackageInfo() { - if (getBundleFile() == getHostData().getBaseBundleFile()) - return ((EclipseBundleData)getHostData()).hasPackageInfo; - FragmentClasspath[] fragCPs = getFragClasspaths(); - if (fragCPs != null) - for (int i = 0; i < fragCPs.length; i++) - if (getBundleFile() == fragCPs[i].getBundleData().getBaseBundleFile()) - return ((EclipseBundleData)fragCPs[i].getBundleData()).hasPackageInfo; - return true; - } - } -} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseElementFactory.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseElementFactory.java deleted file mode 100644 index 3134a5fd0..000000000 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseElementFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2003, 2005 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.core.runtime.adaptor; - -import java.io.IOException; - -import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain; -import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; -import org.eclipse.osgi.framework.adaptor.core.*; - -/** - * Creates EclipseBundleData and EclipseClassLoader objects for the framework adaptor - * <p> - * Clients may extend this class. - * </p> - * @since 3.1 - */ -public class EclipseElementFactory implements AdaptorElementFactory { - - public AbstractBundleData createBundleData(AbstractFrameworkAdaptor adaptor, long id) throws IOException { - return new EclipseBundleData((AbstractFrameworkAdaptor) adaptor, id); - } - - public org.eclipse.osgi.framework.adaptor.BundleClassLoader createClassLoader(ClassLoaderDelegate delegate, BundleProtectionDomain domain, String[] bundleclasspath, AbstractBundleData data) { - return new EclipseClassLoader(delegate, domain, bundleclasspath, data.getAdaptor().getBundleClassLoaderParent(), data); - } - -} 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 965597ff7..e7d74cb2d 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 @@ -118,7 +118,7 @@ public class EclipseStarter { private static final String REFERENCE_PROTOCOL = "reference"; //$NON-NLS-1$ private static final String INITIAL_LOCATION = "initial@"; //$NON-NLS-1$ /** string containing the classname of the adaptor to be used in this framework instance */ - protected static final String DEFAULT_ADAPTOR_CLASS = "org.eclipse.core.runtime.adaptor.EclipseAdaptor"; //$NON-NLS-1$ + protected static final String DEFAULT_ADAPTOR_CLASS = "org.eclipse.osgi.baseadaptor.BaseAdaptor"; //$NON-NLS-1$ private static final int DEFAULT_INITIAL_STARTLEVEL = 6; // default value for legacy purposes private static final String DEFAULT_BUNDLES_STARTLEVEL = "4"; //$NON-NLS-1$ diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/BundleStopper.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/BundleStopper.java index 417cc7aff..a3d70895e 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/BundleStopper.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/BundleStopper.java @@ -4,14 +4,14 @@ * 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.core.runtime.internal.adaptor; import java.util.Hashtable; -import org.eclipse.core.runtime.adaptor.*; +import org.eclipse.osgi.baseadaptor.BaseData; import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; import org.eclipse.osgi.framework.debug.Debug; import org.eclipse.osgi.framework.internal.core.AbstractBundle; @@ -33,18 +33,19 @@ import org.osgi.framework.BundleContext; public class BundleStopper { /* must be a synchronized object */ private Hashtable stoppedBundles; - private BundleDescription[] allToStop = null; - private BundleContext context; + private FrameworkAdaptor adaptor; - public BundleStopper(BundleContext context) { + public BundleStopper(BundleContext context, FrameworkAdaptor adaptor) { this.context = context; + this.adaptor = adaptor; } private void logCycles(Object[][] cycles) { if (!Debug.DEBUG || !Debug.DEBUG_ENABLED) return; + // log cycles if (cycles.length > 0) { StringBuffer cycleText = new StringBuffer("["); //$NON-NLS-1$ @@ -57,15 +58,15 @@ public class BundleStopper { cycleText.insert(cycleText.length() - 1, ']'); } cycleText.setCharAt(cycleText.length() - 1, ']'); - String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_BUNDLESTOPPER_CYCLES_FOUND, cycleText); + String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_BUNDLESTOPPER_CYCLES_FOUND, cycleText); FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, message, 0, null, null); - EclipseAdaptor.getDefault().getFrameworkLog().log(entry); + adaptor.getFrameworkLog().log(entry); } } public void stopBundles() { - allToStop = EclipseAdaptor.getDefault().getState().getResolvedBundles(); - StateHelper stateHelper = EclipseAdaptor.getDefault().getPlatformAdmin().getStateHelper(); + allToStop = adaptor.getState().getResolvedBundles(); + StateHelper stateHelper = adaptor.getPlatformAdmin().getStateHelper(); Object[][] cycles = stateHelper.sortBundles(allToStop); logCycles(cycles); stoppedBundles = new Hashtable(allToStop.length); @@ -76,14 +77,16 @@ public class BundleStopper { // stop all active bundles in the reverse order of Require-Bundle for (int stoppingIndex = allToStop.length - 1; stoppingIndex >= 0; stoppingIndex--) { AbstractBundle toStop = (AbstractBundle) context.getBundle(allToStop[stoppingIndex].getBundleId()); - if (toStop.getBundleId() != 0 && ((EclipseBundleData) toStop.getBundleData()).isAutoStartable()) { + BaseData bundledata = (BaseData) toStop.getBundleData(); + EclipseStorageHook storageHook = (EclipseStorageHook) bundledata.getStorageHook(EclipseStorageHook.KEY); + if (toStop.getBundleId() != 0 && storageHook != null && storageHook.isAutoStartable()) { try { if ((toStop.getState() == Bundle.ACTIVE) && (toStop instanceof BundleHost)) toStop.stop(); } catch (Exception e) { String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_BUNDLESTOPPER_ERROR_STOPPING_BUNDLE, allToStop[stoppingIndex].toString()); FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null); - EclipseAdaptor.getDefault().getFrameworkLog().log(entry); + adaptor.getFrameworkLog().log(entry); } finally { stoppedBundles.put(toStop, toStop); } diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/CachedManifest.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/CachedManifest.java index a460b8abf..1056b86ed 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/CachedManifest.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/CachedManifest.java @@ -4,7 +4,7 @@ * 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 *******************************************************************************/ @@ -12,7 +12,6 @@ package org.eclipse.core.runtime.internal.adaptor; import java.util.Dictionary; import java.util.Enumeration; -import org.eclipse.core.runtime.adaptor.*; import org.eclipse.osgi.framework.adaptor.BundleData; import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; import org.eclipse.osgi.framework.internal.core.Constants; @@ -25,21 +24,21 @@ import org.osgi.framework.*; */ public class CachedManifest extends Dictionary { - Dictionary manifest = null; - EclipseBundleData bundledata; + private Dictionary manifest = null; + private EclipseStorageHook storageHook; - public CachedManifest(EclipseBundleData bundledata) { - this.bundledata = bundledata; + public CachedManifest(EclipseStorageHook storageHook) { + this.storageHook = storageHook; } public Dictionary getManifest() { if (manifest == null) try { - manifest = bundledata.loadManifest(); + manifest = storageHook.createCachedManifest(true); } catch (BundleException e) { - final String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CACHEDMANIFEST_UNEXPECTED_EXCEPTION, bundledata.getLocation()); + final String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CACHEDMANIFEST_UNEXPECTED_EXCEPTION, storageHook.getBaseData().getLocation()); FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null); - EclipseAdaptor.getDefault().getFrameworkLog().log(entry); + storageHook.getAdaptor().getFrameworkLog().log(entry); return null; } return manifest; @@ -67,20 +66,20 @@ public class CachedManifest extends Dictionary { public Object get(Object key) { String keyString = (String) key; if (Constants.BUNDLE_VERSION.equalsIgnoreCase(keyString)) { - Version result = bundledata.getVersion(); + Version result = storageHook.getBaseData().getVersion(); return result == null ? null : result.toString(); } - if (EclipseAdaptor.PLUGIN_CLASS.equalsIgnoreCase(keyString)) - return bundledata.getPluginClass(); + if (Constants.PLUGIN_CLASS.equalsIgnoreCase(keyString)) + return storageHook.getPluginClass(); if (Constants.BUNDLE_SYMBOLICNAME.equalsIgnoreCase(keyString)) { - if ((bundledata.getType() & BundleData.TYPE_SINGLETON) == 0) - return bundledata.getSymbolicName(); - return bundledata.getSymbolicName() + ';' + Constants.SINGLETON_DIRECTIVE + ":=true"; //$NON-NLS-1$ + if ((storageHook.getBaseData().getType() & BundleData.TYPE_SINGLETON) == 0) + return storageHook.getBaseData().getSymbolicName(); + return storageHook.getBaseData().getSymbolicName() + ';' + Constants.SINGLETON_DIRECTIVE + ":=true"; //$NON-NLS-1$ } if (Constants.BUDDY_LOADER.equalsIgnoreCase(keyString)) - return bundledata.getBuddyList(); + return storageHook.getBuddyList(); if (Constants.REGISTERED_POLICY.equalsIgnoreCase(keyString)) - return bundledata.getRegisteredBuddyList(); + return storageHook.getRegisteredBuddyList(); Dictionary result = getManifest(); return result == null ? null : result.get(key); } diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/ClasspathManifest.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/ClasspathManifest.java new file mode 100644 index 000000000..200c365c3 --- /dev/null +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/ClasspathManifest.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.core.runtime.internal.adaptor; + +import java.io.IOException; +import java.io.InputStream; +import java.util.jar.Manifest; +import org.eclipse.osgi.baseadaptor.BaseData; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.loader.*; +import org.eclipse.osgi.framework.util.KeyedElement; + +public class ClasspathManifest implements KeyedElement { + public static final Object KEY = new Object(); + public static final int HASHCODE = KEY.hashCode(); + + private Manifest manifest; + private boolean initialized = false; + + public int getKeyHashCode() { + return HASHCODE; + } + + public boolean compare(KeyedElement other) { + return other.getKey() == KEY; + } + + public Object getKey() { + return KEY; + } + + public Manifest getManifest(ClasspathEntry cpEntry, ClasspathManager loader) { + if (initialized) + return manifest; + if (!hasPackageInfo(cpEntry, loader)) { + initialized = true; + manifest = null; + return manifest; + } + BundleEntry mfEntry = cpEntry.getBundleFile().getEntry(org.eclipse.osgi.framework.internal.core.Constants.OSGI_BUNDLE_MANIFEST); + if (mfEntry != null) + try { + InputStream manIn = mfEntry.getInputStream(); + manifest = new Manifest(manIn); + manIn.close(); + } catch (IOException e) { + // do nothing + } + initialized = true; + return manifest; + } + + private boolean hasPackageInfo(ClasspathEntry cpEntry, ClasspathManager loader) { + BaseData bundledata = null; + if (cpEntry.getBundleFile() == loader.getBaseData().getBundleFile()) + bundledata = loader.getBaseData(); + if (bundledata == null) { + FragmentClasspath[] fragCPs = loader.getFragmentClasspaths(); + if (fragCPs != null) + for (int i = 0; i < fragCPs.length; i++) + if (cpEntry.getBundleFile() == fragCPs[i].getBundleData().getBundleFile()) { + bundledata = fragCPs[i].getBundleData(); + break; + } + } + if (bundledata == null) + return true; + EclipseStorageHook storageHook = (EclipseStorageHook) bundledata.getStorageHook(EclipseStorageHook.KEY); + return storageHook == null ? true : storageHook.hasPackageInfo(); + } + +} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorHook.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorHook.java new file mode 100644 index 000000000..293e41297 --- /dev/null +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorHook.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.core.runtime.internal.adaptor; + +import java.io.*; +import java.net.URLConnection; +import java.util.*; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParserFactory; +import org.eclipse.core.runtime.adaptor.LocationManager; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.hooks.AdaptorHook; +import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; +import org.eclipse.osgi.framework.console.CommandProvider; +import org.eclipse.osgi.framework.debug.Debug; +import org.eclipse.osgi.framework.debug.FrameworkDebugOptions; +import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.log.FrameworkLog; +import org.eclipse.osgi.framework.log.FrameworkLogEntry; +import org.eclipse.osgi.internal.baseadaptor.AdaptorUtil; +import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.osgi.service.pluginconversion.PluginConverter; +import org.eclipse.osgi.service.resolver.PlatformAdmin; +import org.eclipse.osgi.service.runnable.ApplicationLauncher; +import org.eclipse.osgi.service.urlconversion.URLConverter; +import org.osgi.framework.*; + +public class EclipseAdaptorHook implements AdaptorHook, HookConfigurator { + /** The SAX factory name */ + public static final String SAXFACTORYNAME = "javax.xml.parsers.SAXParserFactory"; //$NON-NLS-1$ + /** The DOM factory name */ + public static final String DOMFACTORYNAME = "javax.xml.parsers.DocumentBuilderFactory"; //$NON-NLS-1$ + private static final String RUNTIME_ADAPTOR = FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + "/eclipseadaptor"; //$NON-NLS-1$ + private static final String OPTION_CONVERTER = RUNTIME_ADAPTOR + "/converter/debug"; //$NON-NLS-1$ + private static final String OPTION_LOCATION = RUNTIME_ADAPTOR + "/debug/location"; //$NON-NLS-1$ + + private BaseAdaptor adaptor; + private BundleStopper stopper; + private boolean noXML = false; + + public void frameworkStart(BundleContext context) throws BundleException { + stopper = null; + registerEndorsedXMLParser(context); + Location location = LocationManager.getUserLocation(); + Hashtable locationProperties = new Hashtable(1); + if (location != null) { + locationProperties.put("type", LocationManager.PROP_USER_AREA); //$NON-NLS-1$ + context.registerService(Location.class.getName(), location, locationProperties); + } + location = LocationManager.getInstanceLocation(); + if (location != null) { + locationProperties.put("type", LocationManager.PROP_INSTANCE_AREA); //$NON-NLS-1$ + context.registerService(Location.class.getName(), location, locationProperties); + } + location = LocationManager.getConfigurationLocation(); + if (location != null) { + locationProperties.put("type", LocationManager.PROP_CONFIG_AREA); //$NON-NLS-1$ + context.registerService(Location.class.getName(), location, locationProperties); + } + location = LocationManager.getInstallLocation(); + if (location != null) { + locationProperties.put("type", LocationManager.PROP_INSTALL_AREA); //$NON-NLS-1$ + context.registerService(Location.class.getName(), location, locationProperties); + } + + Dictionary urlProperties = new Hashtable(); + urlProperties.put("protocol", new String[] {"bundleentry", "bundleresource"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + context.registerService(URLConverter.class.getName(), new URLConverterImpl(), urlProperties); + + AdaptorUtil.register(org.eclipse.osgi.service.environment.EnvironmentInfo.class.getName(), EclipseEnvironmentInfo.getDefault(), context); + AdaptorUtil.register(PlatformAdmin.class.getName(), adaptor.getPlatformAdmin(), context); + PluginConverter converter = PluginConverterImpl.getDefault(); + if (converter == null) + converter = new PluginConverterImpl(adaptor, context); + AdaptorUtil.register(PluginConverter.class.getName(), converter, context); + AdaptorUtil.register(CommandProvider.class.getName(), new EclipseCommandProvider(context), context); + AdaptorUtil.register(org.eclipse.osgi.service.localization.BundleLocalization.class.getName(), new BundleLocalizationImpl(), context); + } + + private void registerEndorsedXMLParser(BundleContext bc) { + try { + Class.forName(SAXFACTORYNAME); + bc.registerService(SAXFACTORYNAME, new SaxParsingService(), new Hashtable()); + Class.forName(DOMFACTORYNAME); + bc.registerService(DOMFACTORYNAME, new DomParsingService(), new Hashtable()); + } catch (ClassNotFoundException e) { + noXML = true; + if (Debug.DEBUG && Debug.DEBUG_ENABLED) { + String message = EclipseAdaptorMsg.ECLIPSE_ADAPTOR_ERROR_XML_SERVICE; + adaptor.getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null)); + } + } + } + + private class SaxParsingService implements ServiceFactory { + public Object getService(Bundle bundle, ServiceRegistration registration) { + return SAXParserFactory.newInstance(); + } + + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { + // Do nothing. + } + } + + private class DomParsingService implements ServiceFactory { + public Object getService(Bundle bundle, ServiceRegistration registration) { + return DocumentBuilderFactory.newInstance(); + } + + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { + // Do nothing. + } + } + + public void frameworkStop(BundleContext context) throws BundleException { + // TODO should unregister the services here + printStats(); + if (!noXML) + PluginParser.releaseXMLParsing(); + } + + private void printStats() { + FrameworkDebugOptions debugOptions = FrameworkDebugOptions.getDefault(); + if (debugOptions == null) + return; + String registryParsing = debugOptions.getOption("org.eclipse.core.runtime/registry/parsing/timing/value"); //$NON-NLS-1$ + if (registryParsing != null) + EclipseAdaptorMsg.debug("Time spent in registry parsing: " + registryParsing); //$NON-NLS-1$ + String packageAdminResolution = debugOptions.getOption("debug.packageadmin/timing/value"); //$NON-NLS-1$ + if (packageAdminResolution != null) + System.out.println("Time spent in package admin resolve: " + packageAdminResolution); //$NON-NLS-1$ + String constraintResolution = debugOptions.getOption("org.eclipse.core.runtime.adaptor/resolver/timing/value"); //$NON-NLS-1$ + if (constraintResolution != null) + System.out.println("Time spent resolving the dependency system: " + constraintResolution); //$NON-NLS-1$ + } + + public void frameworkStopping(BundleContext context) { + // Shutdown the ApplicationLauncher service if it is available. + ServiceReference launcherRef = context.getServiceReference(ApplicationLauncher.class.getName()); + if (launcherRef != null) { + ApplicationLauncher launcher = (ApplicationLauncher) context.getService(launcherRef); + // this will force a currently running application to stop. + launcher.shutdown(); + context.ungetService(launcherRef); + } + stopper = new BundleStopper(context, adaptor); + stopper.stopBundles(); + } + + public void addProperties(Properties properties) { + // default the bootdelegation to all packages + if (properties.getProperty(Constants.OSGI_BOOTDELEGATION) == null && !Constants.OSGI_BOOTDELEGATION_NONE.equals(properties.getProperty(Constants.OSGI_JAVA_PROFILE_BOOTDELEGATION))) + properties.put(Constants.OSGI_BOOTDELEGATION, "*"); //$NON-NLS-1$ + if (properties.getProperty(Constants.ECLIPSE_EE_INSTALL_VERIFY) == null) + properties.put(Constants.ECLIPSE_EE_INSTALL_VERIFY, "false"); //$NON-NLS-1$ + } + + public URLConnection mapLocationToURLConnection(String location) throws IOException { + // do nothing + return null; + } + + public void handleRuntimeError(Throwable error) { + // do nothing + } + + public boolean matchDNChain(String pattern, String[] dnChain) { + // do nothing + return false; + } + + public FrameworkLog createFrameworkLog() { + // do nothing + return null; + } + + public void initialize(BaseAdaptor adaptor) { + this.adaptor = adaptor; + // EnvironmentInfo has to be initialized first to compute defaults for system context (see bug 88925) + EclipseEnvironmentInfo.getDefault(); + setDebugOptions(); + } + + private void setDebugOptions() { + FrameworkDebugOptions options = FrameworkDebugOptions.getDefault(); + // may be null if debugging is not enabled + if (options == null) + return; + PluginConverterImpl.DEBUG = options.getBooleanOption(OPTION_CONVERTER, false); + BasicLocation.DEBUG = options.getBooleanOption(OPTION_LOCATION, false); + } + + public BundleStopper getBundleStopper() { + return stopper; + } + + public void addHooks(HookRegistry hookRegistry) { + hookRegistry.addAdaptorHook(this); + } + +} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMessages.properties b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMessages.properties index a9887e71e..a9887e71e 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMessages.properties +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMessages.properties diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMsg.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMsg.java index 37437967a..1c2db825a 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/adaptor/EclipseAdaptorMsg.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMsg.java @@ -8,14 +8,14 @@ * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ -package org.eclipse.core.runtime.adaptor; +package org.eclipse.core.runtime.internal.adaptor; import java.util.Date; import org.eclipse.osgi.service.resolver.*; import org.eclipse.osgi.util.NLS; public class EclipseAdaptorMsg extends NLS { - private static final String BUNDLE_NAME = "org.eclipse.core.runtime.adaptor.EclipseAdaptorMessages"; //$NON-NLS-1$ + private static final String BUNDLE_NAME = "org.eclipse.core.runtime.internal.adaptor.EclipseAdaptorMessages"; //$NON-NLS-1$ public static String ECLIPSE_MISSING_IMPORTED_PACKAGE; public static String ECLIPSE_MISSING_OPTIONAL_REQUIRED_BUNDLE; diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAppLauncher.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAppLauncher.java index b0e46fedf..6ca014891 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAppLauncher.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseAppLauncher.java @@ -11,7 +11,6 @@ package org.eclipse.core.runtime.internal.adaptor; -import org.eclipse.core.runtime.adaptor.EclipseAdaptorMsg; import org.eclipse.core.runtime.adaptor.EclipseStarter; import org.eclipse.osgi.framework.internal.core.FrameworkProperties; import org.eclipse.osgi.internal.profile.Profile; diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseBundleInstaller.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseBundleInstaller.java deleted file mode 100644 index d78998cb5..000000000 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseBundleInstaller.java +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004 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.core.runtime.internal.adaptor; - -import org.eclipse.osgi.framework.adaptor.core.BundleInstaller; -import org.eclipse.osgi.service.resolver.BundleDescription; -import org.osgi.framework.*; - -/** - * Internal class. - */ -//TODO: minimal implementation for now. This could be smarter -public class EclipseBundleInstaller implements BundleInstaller { - BundleContext context; - public EclipseBundleInstaller(BundleContext context) { - this.context = context; - } - - public void installBundle(BundleDescription toInstall) throws BundleException { - context.installBundle(toInstall.getLocation()); - } - - public void uninstallBundle(BundleDescription toUninstallId) throws BundleException { - Bundle toUninstall = context.getBundle(toUninstallId.getBundleId()); - if (toUninstall != null) - toUninstall.uninstall(); - } - - public void updateBundle(BundleDescription toUpdateId) throws BundleException { - Bundle toUpdate = context.getBundle(toUpdateId.getBundleId()); - if (toUpdate != null) - toUpdate.update(); - } -} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseClassLoadingHook.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseClassLoadingHook.java new file mode 100644 index 000000000..bb634ad1c --- /dev/null +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseClassLoadingHook.java @@ -0,0 +1,264 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.core.runtime.internal.adaptor; + +import java.io.File; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.StringTokenizer; +import java.util.jar.Attributes; +import java.util.jar.Manifest; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile; +import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingHook; +import org.eclipse.osgi.baseadaptor.loader.*; +import org.eclipse.osgi.framework.adaptor.BundleProtectionDomain; +import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegate; +import org.eclipse.osgi.framework.internal.core.FrameworkProperties; + +public class EclipseClassLoadingHook implements ClassLoadingHook, HookConfigurator { + private static String[] NL_JAR_VARIANTS = buildNLJarVariants(EclipseEnvironmentInfo.getDefault().getNL()); + private static boolean DEFINE_PACKAGES; + private static final String VARIABLE_DELIM_STRING = "$"; //$NON-NLS-1$ + private static final char VARIABLE_DELIM_CHAR = '$'; + private static final String EXTERNAL_LIB_PREFIX = "external:"; //$NON-NLS-1$ + private static String[] LIB_VARIANTS = buildLibraryVariants(); + + static { + try { + Class.forName("java.lang.Package"); //$NON-NLS-1$ + DEFINE_PACKAGES = true; + } catch (ClassNotFoundException e) { + DEFINE_PACKAGES = false; + } + } + + private static String[] buildLibraryVariants() { + ArrayList result = new ArrayList(); + EclipseEnvironmentInfo info = EclipseEnvironmentInfo.getDefault(); + result.add("ws/" + info.getWS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ + result.add("os/" + info.getOS() + "/" + info.getOSArch() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + result.add("os/" + info.getOS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ + String nl = info.getNL(); + nl = nl.replace('_', '/'); + while (nl.length() > 0) { + result.add("nl/" + nl + "/"); //$NON-NLS-1$ //$NON-NLS-2$ + int i = nl.lastIndexOf('/'); + nl = (i < 0) ? "" : nl.substring(0, i); //$NON-NLS-1$ + } + result.add(""); //$NON-NLS-1$ + return (String[]) result.toArray(new String[result.size()]); + } + + public byte[] processClass(String name, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { + if (!DEFINE_PACKAGES) + return null; + // Define the package if it is not the default package. + int lastIndex = name.lastIndexOf('.'); + if (lastIndex < 0) + return null; + String packageName = name.substring(0, lastIndex); + Package pkg = (Package) manager.getBaseClassLoader().publicGetPackage(packageName); + if (pkg != null) + return null; + + // get info about the package from the classpath entry's manifest. + String specTitle = null, specVersion = null, specVendor = null, implTitle = null, implVersion = null, implVendor = null; + ClasspathManifest cpm = (ClasspathManifest) classpathEntry.getUserObject(ClasspathManifest.KEY); + if (cpm == null) { + cpm = new ClasspathManifest(); + classpathEntry.addUserObject(cpm); + } + Manifest mf = cpm.getManifest(classpathEntry, manager); + if (mf != null) { + Attributes mainAttributes = mf.getMainAttributes(); + String dirName = packageName.replace('.', '/') + '/'; + Attributes packageAttributes = mf.getAttributes(dirName); + boolean noEntry = false; + if (packageAttributes == null) { + noEntry = true; + packageAttributes = mainAttributes; + } + specTitle = packageAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE); + if (specTitle == null && !noEntry) + specTitle = mainAttributes.getValue(Attributes.Name.SPECIFICATION_TITLE); + specVersion = packageAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION); + if (specVersion == null && !noEntry) + specVersion = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VERSION); + specVendor = packageAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR); + if (specVendor == null && !noEntry) + specVendor = mainAttributes.getValue(Attributes.Name.SPECIFICATION_VENDOR); + implTitle = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE); + if (implTitle == null && !noEntry) + implTitle = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE); + implVersion = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION); + if (implVersion == null && !noEntry) + implVersion = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION); + implVendor = packageAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); + if (implVendor == null && !noEntry) + implVendor = mainAttributes.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); + } + // The package is not defined yet define it before we define the class. + // TODO still need to seal packages. + manager.getBaseClassLoader().publicDefinePackage(packageName, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, null); + // not doing any byte processing + return null; + } + + public boolean addClassPathEntry(ArrayList cpEntries, String cp, ClasspathManager hostmanager, BaseData sourcedata, ProtectionDomain sourcedomain) { + String var = hasPrefix(cp); + if (var != null) + // find internal library using eclipse predefined vars + return addInternalClassPath(var, cpEntries, cp, hostmanager, sourcedata, sourcedomain); + if (cp.startsWith(EXTERNAL_LIB_PREFIX)) { + cp = cp.substring(EXTERNAL_LIB_PREFIX.length()); + // find external library using system property substitution + ClasspathEntry cpEntry = hostmanager.getExternalClassPath(substituteVars(cp), sourcedata, sourcedomain); + if (cpEntry != null) { + cpEntries.add(cpEntry); + return true; + } + } + return false; + } + + private boolean addInternalClassPath(String var, ArrayList cpEntries, String cp, ClasspathManager hostloader, BaseData sourcedata, ProtectionDomain sourcedomain) { + if (var.equals("ws")) //$NON-NLS-1$ + return ClasspathManager.addClassPathEntry(cpEntries, "ws/" + EclipseEnvironmentInfo.getDefault().getWS() + cp.substring(4), hostloader, sourcedata, sourcedomain); //$NON-NLS-1$ + if (var.equals("os")) //$NON-NLS-1$ + return ClasspathManager.addClassPathEntry(cpEntries, "os/" + EclipseEnvironmentInfo.getDefault().getOS() + cp.substring(4), hostloader, sourcedata, sourcedomain); //$NON-NLS-1$ + if (var.equals("nl")) { //$NON-NLS-1$ + cp = cp.substring(4); + for (int i = 0; i < NL_JAR_VARIANTS.length; i++) + if (ClasspathManager.addClassPathEntry(cpEntries, "nl/" + NL_JAR_VARIANTS[i] + cp, hostloader, sourcedata, sourcedomain)) //$NON-NLS-1$ + return true; + } + return false; + } + + //return a String representing the string found between the $s + private static String hasPrefix(String libPath) { + if (libPath.startsWith("$ws$")) //$NON-NLS-1$ + return "ws"; //$NON-NLS-1$ + if (libPath.startsWith("$os$")) //$NON-NLS-1$ + return "os"; //$NON-NLS-1$ + if (libPath.startsWith("$nl$")) //$NON-NLS-1$ + return "nl"; //$NON-NLS-1$ + return null; + } + + private static String substituteVars(String cp) { + StringBuffer buf = new StringBuffer(cp.length()); + StringTokenizer st = new StringTokenizer(cp, VARIABLE_DELIM_STRING, true); + boolean varStarted = false; // indicates we are processing a var subtitute + String var = null; // the current var key + while (st.hasMoreElements()) { + String tok = st.nextToken(); + if (VARIABLE_DELIM_STRING.equals(tok)) { + if (!varStarted) { + varStarted = true; // we found the start of a var + var = ""; //$NON-NLS-1$ + } else { + // we have found the end of a var + String prop = null; + // get the value of the var from system properties + if (var != null && var.length() > 0) + prop = FrameworkProperties.getProperty(var); + if (prop != null) + // found a value; use it + buf.append(prop); + else + // could not find a value append the var name w/o delims + buf.append(var == null ? "" : var); //$NON-NLS-1$ + varStarted = false; + var = null; + } + } else { + if (!varStarted) + buf.append(tok); // the token is not part of a var + else + var = tok; // the token is the var key; save the key to process when we find the end token + } + } + if (var != null) + // found a case of $var at the end of the cp with no trailing $; just append it as is. + buf.append(VARIABLE_DELIM_CHAR).append(var); + return buf.toString(); + } + + private static String[] buildNLJarVariants(String nl) { + ArrayList result = new ArrayList(); + nl = nl.replace('_', '/'); + while (nl.length() > 0) { + result.add("nl/" + nl + "/"); //$NON-NLS-1$ //$NON-NLS-2$ + int i = nl.lastIndexOf('/'); + nl = (i < 0) ? "" : nl.substring(0, i); //$NON-NLS-1$ + } + result.add(""); //$NON-NLS-1$ + return (String[]) result.toArray(new String[result.size()]); + } + + public void recordClassDefine(String name, Class clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { + // do nothing + } + + public String findLibrary(BaseData data, String libName) { + if (libName.length() == 0) + return null; + if (libName.charAt(0) == '/' || libName.charAt(0) == '\\') + libName = libName.substring(1); + libName = System.mapLibraryName(libName); + return searchVariants(data, libName); + } + + private String searchVariants(BaseData bundledata, String path) { + for (int i = 0; i < LIB_VARIANTS.length; i++) { + BundleFile baseBundleFile = bundledata.getBundleFile(); + BundleEntry libEntry = baseBundleFile.getEntry(LIB_VARIANTS[i] + path); + if (libEntry != null) { + File libFile = baseBundleFile.getFile(LIB_VARIANTS[i] + path, true); + if (libFile == null) + return null; + // see bug 88697 - HP requires libraries to have executable permissions + if (org.eclipse.osgi.service.environment.Constants.OS_HPUX.equals(EclipseEnvironmentInfo.getDefault().getOS())) { + try { + // use the string array method in case there is a space in the path + Runtime.getRuntime().exec(new String[] {"chmod", "755", libFile.getAbsolutePath()}).waitFor(); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (Exception e) { + e.printStackTrace(); + } + } + return libFile.getAbsolutePath(); + } + } + return null; + } + + public ClassLoader getBundleClassLoaderParent() { + return null; // do nothing + } + + public void addHooks(HookRegistry hookRegistry) { + hookRegistry.addClassLoadingHook(this); + } + + public BaseClassLoader createClassLoader(ClassLoader parent, ClassLoaderDelegate delegate, BundleProtectionDomain domain, BaseData data, String[] bundleclasspath) { + // TODO Auto-generated method stub + return null; + } + + public void initializedClassLoader(BaseClassLoader baseClassLoader, BaseData data) { + // TODO Auto-generated method stub + + } +} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseCommandProvider.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseCommandProvider.java index 6409629a5..c9bbacc73 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseCommandProvider.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseCommandProvider.java @@ -12,7 +12,6 @@ package org.eclipse.core.runtime.internal.adaptor; import java.util.Enumeration; import java.util.Properties; -import org.eclipse.core.runtime.adaptor.EclipseAdaptorMsg; import org.eclipse.osgi.framework.console.CommandInterpreter; import org.eclipse.osgi.framework.console.CommandProvider; import org.eclipse.osgi.framework.internal.core.FrameworkProperties; diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseEnvironmentInfo.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseEnvironmentInfo.java index a6befb2d4..4d01f1878 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseEnvironmentInfo.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseEnvironmentInfo.java @@ -11,7 +11,6 @@ package org.eclipse.core.runtime.internal.adaptor; import java.util.*; -import org.eclipse.core.runtime.adaptor.EclipseAdaptorMsg; import org.eclipse.osgi.framework.internal.core.FrameworkProperties; import org.eclipse.osgi.service.environment.Constants; import org.eclipse.osgi.service.environment.EnvironmentInfo; diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseErrorHandler.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseErrorHandler.java new file mode 100644 index 000000000..bc60f224a --- /dev/null +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseErrorHandler.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.core.runtime.internal.adaptor; + +import java.io.IOException; +import java.net.URLConnection; +import java.util.Properties; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.hooks.AdaptorHook; +import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; +import org.eclipse.osgi.framework.internal.core.FrameworkProperties; +import org.eclipse.osgi.framework.log.FrameworkLog; +import org.eclipse.osgi.framework.log.FrameworkLogEntry; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; + +public class EclipseErrorHandler implements AdaptorHook, HookConfigurator { + // System property used to prevent VM exit when unexpected errors occur + private static final String PROP_EXITONERROR = "eclipse.exitOnError"; //$NON-NLS-1$ + private BaseAdaptor adaptor; + + public void frameworkStart(BundleContext context) throws BundleException { + // do nothing + } + + public void frameworkStop(BundleContext context) throws BundleException { + // do nothing + } + + public void frameworkStopping(BundleContext context) { + // do nothing + } + + public void addProperties(Properties properties) { + // do nothing + } + + public URLConnection mapLocationToURLConnection(String location) throws IOException { + // do nothing + return null; + } + + private boolean isFatalException(Throwable error) { + if (error instanceof VirtualMachineError) { + return true; + } + if (error instanceof ThreadDeath) { + return true; + } + return false; + } + + public void handleRuntimeError(Throwable error) { + // this is the important method to handle errors + boolean exitOnError = false; + try { + // check the prop each time this happens (should NEVER happen!) + exitOnError = Boolean.valueOf(FrameworkProperties.getProperty(EclipseErrorHandler.PROP_EXITONERROR, "true")).booleanValue(); //$NON-NLS-1$ + String message = EclipseAdaptorMsg.ECLIPSE_ADAPTOR_RUNTIME_ERROR; + if (exitOnError && isFatalException(error)) + message += ' ' + EclipseAdaptorMsg.ECLIPSE_ADAPTOR_EXITING; + FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, error, null); + adaptor.getFrameworkLog().log(logEntry); + } catch (Throwable t) { + // we may be in a currupted state and must be able to handle any + // errors (ie OutOfMemoryError) + // that may occur when handling the first error; this is REALLY the + // last resort. + try { + error.printStackTrace(); + t.printStackTrace(); + } catch (Throwable t1) { + // if we fail that then we are beyond help. + } + } finally { + // do the exit outside the try block just incase another runtime + // error was thrown while logging + if (exitOnError && isFatalException(error)) + System.exit(13); + } + } + + public boolean matchDNChain(String pattern, String[] dnChain) { + // do nothing + return false; + } + + public void addHooks(HookRegistry hookRegistry) { + hookRegistry.addAdaptorHook(this); + } + + public FrameworkLog createFrameworkLog() { + // do nothing + return null; + } + + public void initialize(BaseAdaptor adaptor) { + this.adaptor = adaptor; + } +} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLazyStarter.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLazyStarter.java new file mode 100644 index 000000000..a1a5190a3 --- /dev/null +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLazyStarter.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2006 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.core.runtime.internal.adaptor; + +import java.net.URL; +import org.eclipse.core.runtime.internal.stats.StatsManager; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.hooks.AdaptorHook; +import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingStatsHook; +import org.eclipse.osgi.baseadaptor.loader.ClasspathEntry; +import org.eclipse.osgi.baseadaptor.loader.ClasspathManager; +import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; +import org.eclipse.osgi.framework.internal.core.AbstractBundle; +import org.eclipse.osgi.framework.log.FrameworkLogEntry; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; + +public class EclipseLazyStarter implements ClassLoadingStatsHook, HookConfigurator { + + public void preFindLocalClass(String name, ClasspathManager manager) throws ClassNotFoundException { + AbstractBundle bundle = (AbstractBundle) manager.getBaseData().getBundle(); + // If the bundle is active, uninstalled or stopping then the bundle has already + // been initialized (though it may have been destroyed) so just return the class. + if ((bundle.getState() & (Bundle.ACTIVE | Bundle.UNINSTALLED | Bundle.STOPPING)) != 0) + return; + + // The bundle is not active and does not require activation, just return the class + if (!shouldActivateFor(name, manager.getBaseData())) + return; + + // The bundle is starting. Note that if the state changed between the tests + // above and this test (e.g., it was not ACTIVE but now is), that's ok, we will + // just try to start it again (else case). + // TODO need an explanation here of why we duplicated the mechanism + // from the framework rather than just calling start() and letting it sort it out. + if (bundle.getState() == Bundle.STARTING) { + // If the thread trying to load the class is the one trying to activate the bundle, then return the class + if (bundle.testStateChanging(Thread.currentThread()) || bundle.testStateChanging(null)) + return; + + // If it's another thread, we wait and try again. In any case the class is returned. + // The difference is that an exception can be logged. + // TODO do we really need this test? We just did it on the previous line? + if (!bundle.testStateChanging(Thread.currentThread())) { + Thread threadChangingState = bundle.getStateChanging(); + if (StatsManager.TRACE_BUNDLES && threadChangingState != null) + System.out.println("Concurrent startup of bundle " + bundle.getSymbolicName() + " by " + Thread.currentThread() + " and " + threadChangingState.getName() + ". Waiting up to 5000ms for " + threadChangingState + " to finish the initialization."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + long start = System.currentTimeMillis(); + long delay = 5000; + long timeLeft = delay; + while (true) { + try { + Thread.sleep(100); // do not release the classloader lock (bug 86713) + if (bundle.testStateChanging(null) || timeLeft <= 0) + break; + } catch (InterruptedException e) { + //Ignore and keep waiting + } + timeLeft = start + delay - System.currentTimeMillis(); + } + if (timeLeft <= 0 || bundle.getState() != Bundle.ACTIVE) { + String bundleName = bundle.getSymbolicName() == null ? Long.toString(bundle.getBundleId()) : bundle.getSymbolicName(); + String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_CONCURRENT_STARTUP, new Object[] {Thread.currentThread().getName(), name, threadChangingState.getName(), bundleName, Long.toString(delay)}); + manager.getBaseData().getAdaptor().getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, new Exception(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_GENERATED_EXCEPTION), null)); + } + return; + } + } + + //The bundle must be started. + try { + bundle.start(); + } catch (BundleException e) { + String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_ACTIVATION, bundle.getSymbolicName(), Long.toString(bundle.getBundleId())); + manager.getBaseData().getAdaptor().getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null)); + throw new ClassNotFoundException(name, e); + } + return; + } + + public void postFindLocalClass(String name, Class clazz, ClasspathManager manager) { + // do nothing + } + + public void preFindLocalResource(String name, ClasspathManager manager) { + // do nothing + } + + public void postFindLocalResource(String name, URL resource, ClasspathManager manager) { + // do nothing + } + + public void recordClassDefine(String name, Class clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { + // do nothing + } + + private boolean shouldActivateFor(String className, BaseData bundledata) throws ClassNotFoundException { + if (!isAutoStartable(className, bundledata)) + return false; + //Don't reactivate on shut down + if (bundledata.getAdaptor().isStopping()) { + BundleStopper stopper = getBundleStopper(bundledata); + if (stopper != null && stopper.isStopped(bundledata.getBundle())) { + String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_ALREADY_STOPPED, className, bundledata.getSymbolicName()); + throw new ClassNotFoundException(message); + } + } + return true; + } + + private boolean isAutoStartable(String className, BaseData bundledata) { + EclipseStorageHook storageHook = (EclipseStorageHook) bundledata.getStorageHook(EclipseStorageHook.KEY); + if (storageHook == null) + return false; + boolean autoStart = storageHook.isAutoStart(); + String[] autoStartExceptions = storageHook.getAutoStartExceptions(); + // no exceptions, it is easy to figure it out + if (autoStartExceptions == null) + return autoStart; + // otherwise, we need to check if the package is in the exceptions list + int dotPosition = className.lastIndexOf('.'); + // the class has no package name... no exceptions apply + if (dotPosition == -1) + return autoStart; + String packageName = className.substring(0, dotPosition); + // should activate if autoStart and package is not an exception, or if !autoStart and package is exception + return autoStart ^ contains(autoStartExceptions, packageName); + } + + private boolean contains(String[] array, String element) { + for (int i = 0; i < array.length; i++) + if (array[i].equals(element)) + return true; + return false; + } + + private BundleStopper getBundleStopper(BaseData bundledata) { + AdaptorHook[] adaptorhooks = bundledata.getAdaptor().getHookRegistry().getAdaptorHooks(); + for (int i = 0; i < adaptorhooks.length; i++) + if (adaptorhooks[i] instanceof EclipseAdaptorHook) + return ((EclipseAdaptorHook) adaptorhooks[i]).getBundleStopper(); + return null; + } + + public void addHooks(HookRegistry hookRegistry) { + hookRegistry.addClassLoadingStatsHook(this); + } +} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLogHook.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLogHook.java new file mode 100644 index 000000000..706db139a --- /dev/null +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseLogHook.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2006 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.core.runtime.internal.adaptor; + +import java.io.*; +import java.net.URLConnection; +import java.util.*; +import org.eclipse.core.runtime.adaptor.*; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.hooks.AdaptorHook; +import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.internal.core.FrameworkProperties; +import org.eclipse.osgi.framework.log.FrameworkLog; +import org.eclipse.osgi.internal.baseadaptor.AdaptorUtil; +import org.eclipse.osgi.service.datalocation.Location; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; + +public class EclipseLogHook implements HookConfigurator, AdaptorHook { + // The eclipse log file extension */ + private static final String LOG_EXT = ".log"; //$NON-NLS-1$ + BaseAdaptor adaptor; + + public void addHooks(HookRegistry hookRegistry) { + hookRegistry.addAdaptorHook(this); + } + + public void initialize(BaseAdaptor adaptor) { + this.adaptor = adaptor; + } + + public void frameworkStart(BundleContext context) throws BundleException { + AdaptorUtil.register(FrameworkLog.class.getName(), adaptor.getFrameworkLog(), context); + registerPerformanceLog(context); + } + + public void frameworkStop(BundleContext context) throws BundleException { + // TODO should unregister service registered a frameworkStart + } + + public void frameworkStopping(BundleContext context) { + // do nothing + + } + + public void addProperties(Properties properties) { + // do nothing + } + + public URLConnection mapLocationToURLConnection(String location) throws IOException { + // do nothing + return null; + } + + public void handleRuntimeError(Throwable error) { + // TODO Auto-generated method stub + + } + + public boolean matchDNChain(String pattern, String[] dnChain) { + // do nothing + return false; + } + + public FrameworkLog createFrameworkLog() { + FrameworkLog frameworkLog; + String logFileProp = FrameworkProperties.getProperty(EclipseStarter.PROP_LOGFILE); + if (logFileProp != null) { + frameworkLog = new EclipseLog(new File(logFileProp)); + } else { + Location location = LocationManager.getConfigurationLocation(); + File configAreaDirectory = null; + if (location != null) + // TODO assumes the URL is a file: url + configAreaDirectory = new File(location.getURL().getFile()); + + if (configAreaDirectory != null) { + String logFileName = Long.toString(System.currentTimeMillis()) + EclipseLogHook.LOG_EXT; + File logFile = new File(configAreaDirectory, logFileName); + FrameworkProperties.setProperty(EclipseStarter.PROP_LOGFILE, logFile.getAbsolutePath()); + frameworkLog = new EclipseLog(logFile); + } else + frameworkLog = new EclipseLog(); + } + if ("true".equals(FrameworkProperties.getProperty(EclipseStarter.PROP_CONSOLE_LOG))) //$NON-NLS-1$ + frameworkLog.setConsoleLog(true); + return frameworkLog; + } + + private void registerPerformanceLog(BundleContext context) { + Object service = createPerformanceLog(); + String serviceName = FrameworkLog.class.getName(); + Hashtable serviceProperties = new Hashtable(7); + Dictionary headers = context.getBundle().getHeaders(); + + serviceProperties.put(Constants.SERVICE_VENDOR, headers.get(Constants.BUNDLE_VENDOR)); + serviceProperties.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE)); + serviceProperties.put(Constants.SERVICE_PID, context.getBundle().getBundleId() + '.' + service.getClass().getName()); + serviceProperties.put(FrameworkLog.SERVICE_PERFORMANCE, Boolean.TRUE.toString()); + + context.registerService(serviceName, service, serviceProperties); + } + + private FrameworkLog createPerformanceLog() { + String logFileProp = FrameworkProperties.getProperty(EclipseStarter.PROP_LOGFILE); + if (logFileProp != null) { + int lastSlash = logFileProp.lastIndexOf(File.separatorChar); + if (lastSlash > 0) { + String logFile = logFileProp.substring(0, lastSlash + 1) + "performance.log"; //$NON-NLS-1$ + return new EclipseLog(new File(logFile)); + } + } + //if all else fails, write to std err + return new EclipseLog(new PrintWriter(System.err)); + } +} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseStorageHook.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseStorageHook.java new file mode 100644 index 000000000..e619b67ea --- /dev/null +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/EclipseStorageHook.java @@ -0,0 +1,406 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.core.runtime.internal.adaptor; + +import java.io.*; +import java.net.URL; +import java.util.*; +import org.eclipse.core.runtime.adaptor.LocationManager; +import org.eclipse.osgi.baseadaptor.*; +import org.eclipse.osgi.baseadaptor.hooks.StorageHook; +import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; +import org.eclipse.osgi.framework.internal.core.Constants; +import org.eclipse.osgi.framework.internal.core.FrameworkProperties; +import org.eclipse.osgi.framework.log.FrameworkLogEntry; +import org.eclipse.osgi.framework.util.Headers; +import org.eclipse.osgi.framework.util.KeyedElement; +import org.eclipse.osgi.internal.baseadaptor.AdaptorUtil; +import org.eclipse.osgi.service.datalocation.Location; +import org.eclipse.osgi.service.pluginconversion.PluginConversionException; +import org.eclipse.osgi.util.ManifestElement; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.BundleException; +import org.osgi.framework.Version; + +public final class EclipseStorageHook implements StorageHook, HookConfigurator { + // System property used to check timestamps of the bundles in the configuration + private static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$ + private static final int STORAGE_VERION = 1; + + public static final String KEY = EclipseStorageHook.class.getName(); + public static final int HASHCODE = KEY.hashCode(); + + /** data to detect modification made in the manifest */ + private long manifestTimeStamp = 0; + private byte manifestType = PluginConverterImpl.MANIFEST_TYPE_UNKNOWN; + + private BaseData bundledata; + + /** the Plugin-Class header */ + private String pluginClass = null; + /** Eclipse-LazyStart header */ + private boolean autoStart; + private String[] autoStartExceptions; + /** shortcut to know if a bundle has a buddy */ + private String buddyList; + /** shortcut to know if a bundle is a registrant to a registered policy */ + private String registeredBuddyList; + /** shortcut to know if the bundle manifest has package info */ + private boolean hasPackageInfo; + + public int getStorageVersion() { + return STORAGE_VERION; + } + + public StorageHook create(BaseData bundledata) throws BundleException { + EclipseStorageHook storageHook = new EclipseStorageHook(); + storageHook.bundledata = bundledata; + return storageHook; + } + + public void initialize(Dictionary manifest) throws BundleException { + String lazyStart = (String) manifest.get(Constants.ECLIPSE_LAZYSTART); + if (lazyStart == null) + lazyStart = (String) manifest.get(Constants.ECLIPSE_AUTOSTART); + parseLazyStart(this, lazyStart); + pluginClass = (String) manifest.get(Constants.PLUGIN_CLASS); + buddyList = (String) manifest.get(Constants.BUDDY_LOADER); + registeredBuddyList = (String) manifest.get(Constants.REGISTERED_POLICY); + hasPackageInfo = hasPackageInfo(bundledata.getEntry(Constants.OSGI_BUNDLE_MANIFEST)); + String genFrom = (String) manifest.get(PluginConverterImpl.GENERATED_FROM); + if (genFrom != null) { + ManifestElement generatedFrom = ManifestElement.parseHeader(PluginConverterImpl.GENERATED_FROM, genFrom)[0]; + if (generatedFrom != null) { + manifestTimeStamp = Long.parseLong(generatedFrom.getValue()); + manifestType = Byte.parseByte(generatedFrom.getAttribute(PluginConverterImpl.MANIFEST_TYPE_ATTRIBUTE)); + } + } + } + + public StorageHook load(BaseData target, DataInputStream in) throws IOException { + EclipseStorageHook storageHook = new EclipseStorageHook(); + storageHook.bundledata = target; + storageHook.autoStart = in.readBoolean(); + int exceptionsCount = in.readInt(); + storageHook.autoStartExceptions = exceptionsCount > 0 ? new String[exceptionsCount] : null; + for (int i = 0; i < exceptionsCount; i++) + storageHook.autoStartExceptions[i] = in.readUTF(); + storageHook.hasPackageInfo = in.readBoolean(); + storageHook.buddyList = AdaptorUtil.readString(in, false); + storageHook.registeredBuddyList = AdaptorUtil.readString(in, false); + storageHook.pluginClass = AdaptorUtil.readString(in, false); + storageHook.manifestTimeStamp = in.readLong(); + storageHook.manifestType = in.readByte(); + return storageHook; + } + + public void save(DataOutputStream out) throws IOException { + if (bundledata == null) + throw new IllegalStateException(); + out.writeBoolean(isAutoStart()); + String[] autoStartExceptions = getAutoStartExceptions(); + if (autoStartExceptions == null) + out.writeInt(0); + else { + out.writeInt(autoStartExceptions.length); + for (int i = 0; i < autoStartExceptions.length; i++) + out.writeUTF(autoStartExceptions[i]); + } + out.writeBoolean(hasPackageInfo()); + AdaptorUtil.writeStringOrNull(out, getBuddyList()); + AdaptorUtil.writeStringOrNull(out, getRegisteredBuddyList()); + AdaptorUtil.writeStringOrNull(out, getPluginClass()); + out.writeLong(getManifestTimeStamp()); + out.writeByte(getManifestType()); + } + + public int getKeyHashCode() { + return HASHCODE; + } + + public boolean compare(KeyedElement other) { + return other.getKey() == KEY; + } + + public Object getKey() { + return KEY; + } + + public boolean isAutoStart() { + return autoStart; + } + + public String[] getAutoStartExceptions() { + return autoStartExceptions; + } + + public String getBuddyList() { + return buddyList; + } + + public boolean hasPackageInfo() { + return hasPackageInfo; + } + + public String getPluginClass() { + return pluginClass; + } + + public String getRegisteredBuddyList() { + return registeredBuddyList; + } + + public long getManifestTimeStamp() { + return manifestTimeStamp; + } + + public byte getManifestType() { + return manifestType; + } + + /** + * Checks whether this bundle is auto started for all resource/class loads or only for a + * subset of resource/classloads + * @return true if the bundle is auto started; false otherwise + */ + public boolean isAutoStartable() { + return autoStart || (autoStartExceptions != null && autoStartExceptions.length > 0); + } + + private void parseLazyStart(EclipseStorageHook storageHook, String headerValue) { + storageHook.autoStart = false; + storageHook.autoStartExceptions = null; + ManifestElement[] allElements = null; + try { + allElements = ManifestElement.parseHeader(Constants.ECLIPSE_LAZYSTART, headerValue); + } catch (BundleException e) { + // just use the default settings (no auto activation) + String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CLASSLOADER_CANNOT_GET_HEADERS, storageHook.bundledata.getLocation()); + bundledata.getAdaptor().getFrameworkLog().log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, message, 0, e, null)); + } + //Eclipse-AutoStart not found... + if (allElements == null) + return; + // the single value for this element should be true|false + storageHook.autoStart = "true".equalsIgnoreCase(allElements[0].getValue()); //$NON-NLS-1$ + // look for any exceptions (the attribute) to the autoActivate setting + String exceptionsValue = allElements[0].getAttribute(Constants.ECLIPSE_LAZYSTART_EXCEPTIONS); + if (exceptionsValue == null) + return; + StringTokenizer tokenizer = new StringTokenizer(exceptionsValue, ","); //$NON-NLS-1$ + int numberOfTokens = tokenizer.countTokens(); + storageHook.autoStartExceptions = new String[numberOfTokens]; + for (int i = 0; i < numberOfTokens; i++) + storageHook.autoStartExceptions[i] = tokenizer.nextToken().trim(); + } + + // Used to check the bundle manifest file for any package information. + // This is used when '.' is on the Bundle-ClassPath to prevent reading + // the bundle manifest for pacakge information when loading classes. + private static boolean hasPackageInfo(URL url) { + if (url == null) + return false; + BufferedReader br = null; + try { + br = new BufferedReader(new InputStreamReader(url.openStream())); + String line; + while ((line = br.readLine()) != null) { + if (line.startsWith("Specification-Title: ") || line.startsWith("Specification-Version: ") || line.startsWith("Specification-Vendor: ") || line.startsWith("Implementation-Title: ") || line.startsWith("Implementation-Version: ") || line.startsWith("Implementation-Vendor: ")) //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ + return true; + } + } catch (IOException ioe) { + // do nothing + } finally { + if (br != null) + try { + br.close(); + } catch (IOException e) { + // do nothing + } + } + return false; + } + + public void addHooks(HookRegistry hookRegistry) { + hookRegistry.addStorageHook(this); + } + + private void checkTimeStamp() throws IllegalArgumentException { + if (!checkManifestTimeStamp()) + throw new IllegalArgumentException(); + } + + private boolean checkManifestTimeStamp() { + if (!"true".equalsIgnoreCase(FrameworkProperties.getProperty(EclipseStorageHook.PROP_CHECK_CONFIG))) //$NON-NLS-1$ + return true; + if (PluginConverterImpl.getTimeStamp(bundledata.getBundleFile().getBaseFile(), getManifestType()) == getManifestTimeStamp()) { + if ((getManifestType() & (PluginConverterImpl.MANIFEST_TYPE_JAR | PluginConverterImpl.MANIFEST_TYPE_BUNDLE)) != 0) + return true; + String cacheLocation = FrameworkProperties.getProperty(LocationManager.PROP_MANIFEST_CACHE); + Location parentConfiguration = LocationManager.getConfigurationLocation().getParentLocation(); + if (parentConfiguration != null) { + try { + return checkManifestAndParent(cacheLocation, bundledata.getSymbolicName(), bundledata.getVersion().toString(), getManifestType()) != null; + } catch (BundleException e) { + return false; + } + } + File cacheFile = new File(cacheLocation, bundledata.getSymbolicName() + '_' + bundledata.getVersion() + ".MF"); //$NON-NLS-1$ + if (cacheFile.isFile()) + return true; + } + return false; + } + + private Headers checkManifestAndParent(String cacheLocation, String symbolicName, String version, byte inputType) throws BundleException { + Headers result = basicCheckManifest(cacheLocation, symbolicName, version, inputType); + if (result != null) + return result; + Location parentConfiguration = null; + if ((parentConfiguration = LocationManager.getConfigurationLocation().getParentLocation()) != null) + result = basicCheckManifest(new File(parentConfiguration.getURL().getFile(), FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME + '/' + LocationManager.MANIFESTS_DIR).toString(), symbolicName, version, inputType); + return result; + } + + private Headers basicCheckManifest(String cacheLocation, String symbolicName, String version, byte inputType) throws BundleException { + File currentFile = new File(cacheLocation, symbolicName + '_' + version + ".MF"); //$NON-NLS-1$ + if (PluginConverterImpl.upToDate(currentFile, bundledata.getBundleFile().getBaseFile(), inputType)) { + try { + return Headers.parseManifest(new FileInputStream(currentFile)); + } catch (FileNotFoundException e) { + // do nothing. + } + } + return null; + } + + Dictionary createCachedManifest(boolean firstTime) throws BundleException { + return firstTime ? getGeneratedManifest() : new CachedManifest(this); + } + + public Dictionary getGeneratedManifest() throws BundleException { + Dictionary builtIn = AdaptorUtil.loadManifestFrom(bundledata); + if (builtIn != null) { + // the bundle has a built-in manifest - we may not have to generate one + if (!isComplete(builtIn)) { + Dictionary generatedManifest = generateManifest(builtIn); + if (generatedManifest != null) + return generatedManifest; + } + // the manifest is complete or we could not complete it - take it as it is + manifestType = PluginConverterImpl.MANIFEST_TYPE_BUNDLE; + if (bundledata.getBundleFile().getBaseFile().isFile()) { + manifestTimeStamp = bundledata.getBundleFile().getBaseFile().lastModified(); + manifestType |= PluginConverterImpl.MANIFEST_TYPE_JAR; + } else + manifestTimeStamp = bundledata.getBundleFile().getEntry(Constants.OSGI_BUNDLE_MANIFEST).getTime(); + return builtIn; + } + Dictionary result = generateManifest(null); + if (result == null) + throw new BundleException(NLS.bind(EclipseAdaptorMsg.ECLIPSE_DATA_MANIFEST_NOT_FOUND, bundledata.getLocation())); + return result; + } + + private Dictionary generateManifest(Dictionary builtIn) throws BundleException { + String cacheLocation = FrameworkProperties.getProperty(LocationManager.PROP_MANIFEST_CACHE); + if (bundledata.getSymbolicName() != null) { + Headers existingHeaders = checkManifestAndParent(cacheLocation, bundledata.getSymbolicName(), bundledata.getVersion().toString(), manifestType); + if (existingHeaders != null) + return existingHeaders; + } + + PluginConverterImpl converter = PluginConverterImpl.getDefault(); + if (converter == null) + converter = new PluginConverterImpl(bundledata.getAdaptor(), bundledata.getAdaptor().getContext()); + + Dictionary generatedManifest; + try { + generatedManifest = converter.convertManifest(bundledata.getBundleFile().getBaseFile(), true, null, true, null); + } catch (PluginConversionException pce) { + String message = NLS.bind(EclipseAdaptorMsg.ECLIPSE_CONVERTER_ERROR_CONVERTING, bundledata.getBundleFile().getBaseFile()); + throw new BundleException(message, pce); + } + + //Now we know the symbolicId and the version of the bundle, we check to see if don't have a manifest for it already + Version version = Version.parseVersion((String) generatedManifest.get(Constants.BUNDLE_VERSION)); + String symbolicName = ManifestElement.parseHeader(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME, (String) generatedManifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME))[0].getValue(); + ManifestElement generatedFrom = ManifestElement.parseHeader(PluginConverterImpl.GENERATED_FROM, (String) generatedManifest.get(PluginConverterImpl.GENERATED_FROM))[0]; + Headers existingHeaders = checkManifestAndParent(cacheLocation, symbolicName, version.toString(), Byte.parseByte(generatedFrom.getAttribute(PluginConverterImpl.MANIFEST_TYPE_ATTRIBUTE))); + //We don't have a manifest. + manifestTimeStamp = Long.parseLong(generatedFrom.getValue()); + manifestType = Byte.parseByte(generatedFrom.getAttribute(PluginConverterImpl.MANIFEST_TYPE_ATTRIBUTE)); + if (bundledata.getAdaptor().isReadOnly() || existingHeaders != null) + return existingHeaders; + + //merge the original manifest with the generated one + if (builtIn != null) { + Enumeration keysEnum = builtIn.keys(); + while (keysEnum.hasMoreElements()) { + Object key = keysEnum.nextElement(); + generatedManifest.put(key, builtIn.get(key)); + } + } + + //write the generated manifest + File bundleManifestLocation = new File(cacheLocation, symbolicName + '_' + version.toString() + ".MF"); //$NON-NLS-1$ + try { + converter.writeManifest(bundleManifestLocation, generatedManifest, true); + } catch (Exception e) { + //TODO Need to log + } + return generatedManifest; + + } + + private boolean isComplete(Dictionary manifest) { + // a manifest is complete if it has a Bundle-SymbolicName entry... + if (manifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME) != null) + return true; + // ...or it does not have a plugin/fragment manifest where to get the other entries from + return bundledata.getEntry(PluginConverterImpl.PLUGIN_MANIFEST) == null && bundledata.getEntry(PluginConverterImpl.FRAGMENT_MANIFEST) == null; + } + + public BaseData getBaseData() { + return bundledata; + } + + public void copy(StorageHook storageHook) { + // copy nothing all must be re-read from a manifest + } + + public void validate() throws IllegalArgumentException { + checkTimeStamp(); + } + + public FrameworkAdaptor getAdaptor() { + if (bundledata != null) + return bundledata.getAdaptor(); + return null; + } + + public Dictionary getManifest(boolean firstLoad) throws BundleException { + return createCachedManifest(firstLoad); + } + + public boolean forgetStatusChange(int status) { + return isAutoStartable(); + } + + public boolean forgetStartLevelChange(int startlevel) { + return false; + } + + public boolean matchDNChain(String pattern) { + return false; + } +} diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/Locker_JavaNio.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/Locker_JavaNio.java index ee8ce4914..6b7ed956b 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/Locker_JavaNio.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/Locker_JavaNio.java @@ -12,7 +12,6 @@ package org.eclipse.core.runtime.internal.adaptor; import java.io.*; import java.nio.channels.FileLock; -import org.eclipse.core.runtime.adaptor.EclipseAdaptorMsg; import org.eclipse.osgi.util.NLS; /** diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/PluginConverterImpl.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/PluginConverterImpl.java index 767c06262..37200679d 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/PluginConverterImpl.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/PluginConverterImpl.java @@ -18,10 +18,10 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.eclipse.core.runtime.adaptor.*; import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; -import org.eclipse.osgi.framework.adaptor.core.DevClassPathHelper; import org.eclipse.osgi.framework.internal.core.Constants; import org.eclipse.osgi.framework.internal.core.FrameworkProperties; import org.eclipse.osgi.framework.log.FrameworkLogEntry; +import org.eclipse.osgi.internal.baseadaptor.DevClassPathHelper; import org.eclipse.osgi.service.pluginconversion.PluginConversionException; import org.eclipse.osgi.service.pluginconversion.PluginConverter; import org.eclipse.osgi.service.resolver.VersionRange; diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/PluginParser.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/PluginParser.java index f509a13c3..038eaf067 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/PluginParser.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/adaptor/PluginParser.java @@ -13,7 +13,6 @@ package org.eclipse.core.runtime.internal.adaptor; import java.io.InputStream; import java.util.*; import javax.xml.parsers.SAXParserFactory; -import org.eclipse.core.runtime.adaptor.EclipseAdaptorMsg; import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; import org.eclipse.osgi.framework.log.FrameworkLogEntry; import org.eclipse.osgi.util.NLS; diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/stats/StatsManager.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/stats/StatsManager.java index 5cb19f03f..998d2488b 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/stats/StatsManager.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/core/runtime/internal/stats/StatsManager.java @@ -11,14 +11,22 @@ package org.eclipse.core.runtime.internal.stats; import java.io.*; +import java.net.URL; import java.util.*; +import org.eclipse.osgi.baseadaptor.HookConfigurator; +import org.eclipse.osgi.baseadaptor.HookRegistry; +import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; +import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingStatsHook; +import org.eclipse.osgi.baseadaptor.loader.ClasspathEntry; +import org.eclipse.osgi.baseadaptor.loader.ClasspathManager; import org.eclipse.osgi.framework.adaptor.BundleWatcher; import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; +import org.eclipse.osgi.framework.debug.Debug; import org.eclipse.osgi.framework.debug.FrameworkDebugOptions; import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.Bundle; -public class StatsManager implements BundleWatcher { +public class StatsManager implements BundleWatcher, HookConfigurator, ClassLoadingStatsHook { // This connect bundles and their info, and so allows to access the info without running through // the bundle registry. This map only contains activated bundles. The key is the bundle Id private Hashtable bundles = new Hashtable(20); @@ -97,6 +105,17 @@ public class StatsManager implements BundleWatcher { bundle.setDuringStartup(booting); } + public void watchBundle(Bundle bundle, int type) { + switch (type) { + case BundleWatcher.START_ACTIVATION : + startActivation(bundle); + break; + case BundleWatcher.END_ACTIVATION : + endActivation(bundle); + break; + } + } + public void startActivation(Bundle bundle) { // should be called from a synchronized location to protect against concurrent updates BundleStats info = findBundle(bundle.getSymbolicName(), bundle.getBundleId()); @@ -177,4 +196,39 @@ public class StatsManager implements BundleWatcher { return (BundleStats) bundles.get(new Long(id)); } + public void preFindLocalClass(String name, ClasspathManager manager) throws ClassNotFoundException { + if (StatsManager.MONITOR_CLASSES) //Support for performance analysis + ClassloaderStats.startLoadingClass(getClassloaderId(manager), name); + } + + public void postFindLocalClass(String name, Class clazz, ClasspathManager manager) { + if (StatsManager.MONITOR_CLASSES) + ClassloaderStats.endLoadingClass(getClassloaderId(manager), name, clazz != null); + } + + public void preFindLocalResource(String name, ClasspathManager manager) { + // do nothing + } + + public void postFindLocalResource(String name, URL resource, ClasspathManager manager) { + if (StatsManager.MONITOR_RESOURCES) + if (resource != null && name.endsWith(".properties")) //$NON-NLS-1$ + ClassloaderStats.loadedBundle(getClassloaderId(manager), new ResourceBundleStats(getClassloaderId(manager), name, resource)); + return; + } + + public void recordClassDefine(String name, Class clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { + // do nothing + } + + private String getClassloaderId(ClasspathManager loader) { + return loader.getBaseData().getSymbolicName(); + } + + public void addHooks(HookRegistry hookRegistry) { + if (Debug.MONITOR_ACTIVATION) + hookRegistry.addWatcher(StatsManager.getDefault()); + if (StatsManager.MONITOR_CLASSES || StatsManager.MONITOR_RESOURCES) + hookRegistry.addClassLoadingStatsHook(StatsManager.getDefault()); + } } diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/service/datalocation/Location.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/service/datalocation/Location.java index b8fba576e..6b1ebe3a9 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/service/datalocation/Location.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/service/datalocation/Location.java @@ -128,6 +128,7 @@ public interface Location { * Locking a location is advisory only. That is, it does not prevent other applications from * modifying the same location * </p> + * @return true if the lock could be acquired; otherwise false is returned * * @exception IOException if there was an unexpected problem while acquiring the lock */ diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/service/localization/BundleLocalization.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/service/localization/BundleLocalization.java index 7e4fa4586..2061517ba 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/service/localization/BundleLocalization.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/service/localization/BundleLocalization.java @@ -26,6 +26,8 @@ public interface BundleLocalization { /** * The getLocalization method gets a ResourceBundle object for the given * locale and bundle. + * @param bundle the bundle to get localization for + * @param locale the name of the locale to get * * @return A <code>ResourceBundle</code> object for the given bundle and locale. * If <code>null</code> is passed for the locale parameter, the default locale is used. diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/storagemanager/ManagedOutputStream.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/storagemanager/ManagedOutputStream.java index 7a3aaaf0c..4c4cf045d 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/storagemanager/ManagedOutputStream.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/storagemanager/ManagedOutputStream.java @@ -46,6 +46,7 @@ public final class ManagedOutputStream extends FilterOutputStream { * a set returned by {@link StorageManager#getOutputStreamSet(String[])} then * the storage manager will only be updated with the new content after all * of the managed output streams in the set are closed successfully. + * @see FilterOutputStream#close() */ public void close() throws IOException { manager.closeOutputStream(this); diff --git a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/storagemanager/StorageManager.java b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/storagemanager/StorageManager.java index 1ab2e7901..09f973563 100644 --- a/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/storagemanager/StorageManager.java +++ b/bundles/org.eclipse.osgi/eclipseAdaptor/src/org/eclipse/osgi/storagemanager/StorageManager.java @@ -12,9 +12,7 @@ package org.eclipse.osgi.storagemanager; import java.io.*; import java.util.*; -import org.eclipse.core.runtime.adaptor.EclipseAdaptorMsg; -import org.eclipse.core.runtime.internal.adaptor.BasicLocation; -import org.eclipse.core.runtime.internal.adaptor.Locker; +import org.eclipse.core.runtime.internal.adaptor.*; import org.eclipse.osgi.framework.internal.reliablefile.*; import org.eclipse.osgi.framework.util.SecureAction; @@ -459,6 +457,7 @@ public final class StorageManager { * Removes the given managed file from management by this storage manager. * * @param managedFile the managed file to remove + * @throws IOException if an error occured removing the managed file */ public void remove(String managedFile) throws IOException { if (!open) @@ -686,6 +685,7 @@ public final class StorageManager { * This methods opens the storage manager. * This method must be called before any operation on the storage manager. * @param wait indicates if the open operation must wait in case of contention on the lock file. + * @throws IOException if an error occured opening the storage manager */ public void open(boolean wait) throws IOException { if (openCleanup) diff --git a/bundles/org.eclipse.osgi/hookconfigurators.properties b/bundles/org.eclipse.osgi/hookconfigurators.properties new file mode 100644 index 000000000..b01d3377f --- /dev/null +++ b/bundles/org.eclipse.osgi/hookconfigurators.properties @@ -0,0 +1,20 @@ +############################################################################### +# Copyright (c) 2005, 2006 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 +############################################################################### +hook.configurators= \ + org.eclipse.osgi.internal.baseadaptor.BaseHookConfigurator,\ + org.eclipse.osgi.internal.baseadaptor.DevClassLoadingHook,\ + org.eclipse.core.runtime.internal.adaptor.EclipseStorageHook,\ + org.eclipse.core.runtime.internal.adaptor.EclipseLogHook,\ + org.eclipse.core.runtime.internal.adaptor.EclipseErrorHandler,\ + org.eclipse.core.runtime.internal.adaptor.EclipseAdaptorHook,\ + org.eclipse.core.runtime.internal.adaptor.EclipseClassLoadingHook,\ + org.eclipse.core.runtime.internal.adaptor.EclipseLazyStarter,\ + org.eclipse.core.runtime.internal.stats.StatsManager diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java index 536f34bc2..b8c75671c 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/BundleDescriptionImpl.java @@ -13,7 +13,7 @@ package org.eclipse.osgi.internal.resolver; import java.io.IOException; import java.util.*; import org.eclipse.osgi.framework.internal.core.Constants; -import org.eclipse.osgi.framework.internal.core.KeyedElement; +import org.eclipse.osgi.framework.util.KeyedElement; import org.eclipse.osgi.service.resolver.*; public class BundleDescriptionImpl extends BaseDescriptionImpl implements BundleDescription, KeyedElement { @@ -323,13 +323,15 @@ public class BundleDescriptionImpl extends BaseDescriptionImpl implements Bundle } protected synchronized void addDependency(BaseDescriptionImpl dependency) { - if (dependencies == null) - dependencies = new ArrayList(10); BundleDescriptionImpl bundle; if (dependency instanceof ExportPackageDescription) bundle = (BundleDescriptionImpl) ((ExportPackageDescription) dependency).getExporter(); else bundle = (BundleDescriptionImpl) dependency; + if (bundle == this) + return; + if (dependencies == null) + dependencies = new ArrayList(10); if (!dependencies.contains(bundle)) { bundle.addDependent(this); dependencies.add(bundle); diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateDeltaImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateDeltaImpl.java index 5e930434c..4ddaabed0 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateDeltaImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateDeltaImpl.java @@ -86,7 +86,6 @@ public class StateDeltaImpl implements StateDelta { } void recordBundleRemovalPending(BundleDescriptionImpl removed) { - removed.setStateBit(BundleDescriptionImpl.REMOVAL_PENDING, true); BundleDeltaImpl change = (BundleDeltaImpl) changes.get(removed); if (change == null) { changes.put(removed, new BundleDeltaImpl(removed, BundleDelta.REMOVAL_PENDING)); diff --git a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java index d5a7f59c2..c4c2186ba 100644 --- a/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java +++ b/bundles/org.eclipse.osgi/resolver/src/org/eclipse/osgi/internal/resolver/StateImpl.java @@ -12,10 +12,12 @@ package org.eclipse.osgi.internal.resolver; import java.util.*; -import org.eclipse.osgi.framework.adaptor.core.StateManager; import org.eclipse.osgi.framework.debug.Debug; import org.eclipse.osgi.framework.debug.FrameworkDebugOptions; import org.eclipse.osgi.framework.internal.core.*; +import org.eclipse.osgi.framework.util.KeyedElement; +import org.eclipse.osgi.framework.util.KeyedHashSet; +import org.eclipse.osgi.internal.baseadaptor.StateManager; import org.eclipse.osgi.service.resolver.*; import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.BundleException; @@ -64,6 +66,7 @@ public abstract class StateImpl implements State { if (!bundleDescriptions.remove(existing)) return false; resolvedBundles.remove(existing); + existing.setStateBit(BundleDescriptionImpl.REMOVAL_PENDING, true); if (!basicAddBundle(newDescription)) return false; resolved = false; @@ -105,6 +108,7 @@ public abstract class StateImpl implements State { resolvedBundles.remove((KeyedElement) toRemove); resolved = false; getDelta().recordBundleRemoved((BundleDescriptionImpl) toRemove); + ((BundleDescriptionImpl) toRemove).setStateBit(BundleDescriptionImpl.REMOVAL_PENDING, true); if (resolver != null) { boolean pending = toRemove.getDependents().length > 0; resolver.bundleRemoved(toRemove, pending); @@ -385,6 +389,7 @@ public abstract class StateImpl implements State { boolean basicAddBundle(BundleDescription description) { ((BundleDescriptionImpl) description).setContainingState(this); + ((BundleDescriptionImpl) description).setStateBit(BundleDescriptionImpl.REMOVAL_PENDING, false); return bundleDescriptions.add((BundleDescriptionImpl) description); } diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMessages.properties b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMessages.properties new file mode 100644 index 000000000..a9887e71e --- /dev/null +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMessages.properties @@ -0,0 +1,105 @@ +############################################################################### +# Copyright (c) 2004 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 +############################################################################### + +#External Messages for EN locale + +#EclipseAdaptor messages +ECLIPSE_ADAPTOR_ERROR_XML_SERVICE=Error registering XML parser services. +ECLIPSE_ADAPTOR_RUNTIME_ERROR=An unexpected runtime error has occurred. +ECLIPSE_ADAPTOR_EXITING=The application will terminate. + +#EclipseStarter messages +ECLIPSE_STARTUP_BUNDLE_NOT_FOUND=Bundle {0} not found. +ECLIPSE_STARTUP_ROOTS_NOT_RESOLVED=One or more bundles are not resolved because the following root constraints are not resolved: +ECLIPSE_STARTUP_ALL_NOT_RESOLVED=The following is a complete list of bundles which are not resolved, see the prior log entry for the root cause if it exists: +ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED=Bundle {0} was not resolved. +ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_ACTIVE=Bundle {0} is not active. +ECLIPSE_STARTUP_ERROR_NO_APPLICATION=Unable to acquire application service. +#Don't use double quotes in the ECLIPSE_STARTUP_ERROR_CHECK_LOG. (See bug 86085) +ECLIPSE_STARTUP_ERROR_CHECK_LOG=An error has occurred. See the log file\n{0}. +ECLIPSE_STARTUP_ALREADY_RUNNING=Platform already running +ECLIPSE_STARTUP_NOT_RUNNING=Platform not running +ECLIPSE_STARTUP_STARTUP_ERROR=Startup error +ECLIPSE_STARTUP_APP_ERROR=Application error +ECLIPSE_STARTUP_SHUTDOWN_ERROR=Shutdown error +ECLIPSE_STARTUP_INVALID_PORT=Invalid console port: {0} +ECLIPSE_STARTUP_FAILED_FIND=Failed to find/start: {0} +ECLIPSE_STARTUP_FAILED_INSTALL=Error installing bundle: {0} +ECLIPSE_STARTUP_FAILED_UNINSTALL=Error uninstalling bundle: {0} +ECLIPSE_STARTUP_FAILED_START=Error starting bundle: {0} +ECLIPSE_STARTUP_FILEMANAGER_OPEN_ERROR=Error reading configuration: {0} +ECLIPSE_STARTUP_PROPS_NOT_SET=Cannot start without the following system properties set: {0} + +#EclipseBundleData messages +ECLIPSE_DATA_MANIFEST_NOT_FOUND=Manifest not found: {0} +ECLIPSE_DATA_ERROR_READING_MANIFEST=Error reading manifest for bundle at the location: {0} + +#Console extension +ECLIPSE_CONSOLE_NO_BUNDLE_SPECIFIED_ERROR=No bundle specified!. +ECLIPSE_CONSOLE_CANNOT_FIND_BUNDLE_ERROR=Cannot find bundle {0}. +ECLIPSE_CONSOLE_NO_CONSTRAINTS_NO_PLATFORM_ADMIN_MESSAGE=No unresolved constraints [PlatformAdmin service is not registered]. +ECLIPSE_CONSOLE_NO_CONSTRAINTS=No unresolved constraints. +ECLIPSE_CONSOLE_OTHER_VERSION=Bundle {0} was picked instead. +ECLIPSE_CONSOLE_COMMANDS_HEADER=Eclipse Runtime commands. +ECLIPSE_CONSOLE_HELP_DIAG_COMMAND_DESCRIPTION=Displays unsatisfied constraints for the specified bundle(s). +ECLIPSE_CONSOLE_HELP_ACTIVE_COMMAND_DESCRIPTION=Displays a list of all bundles currently in the ACTIVE state. +ECLIPSE_CONSOLE_HELP_GETPROP_COMMAND_DESCRIPTION={ name } - Displays the system properties with the given name, or all of them. +ECLIPSE_CONSOLE_BUNDLES_ACTIVE={0} active bundle(s). + +#Bundle resolution messages +ECLIPSE_MISSING_OPTIONAL_REQUIRED_BUNDLE=Missing optionally required bundle {0}. +ECLIPSE_MISSING_REQUIRED_BUNDLE=Missing required bundle {0}. +ECLIPSE_MISSING_IMPORTED_PACKAGE=Missing imported package {0}. +ECLIPSE_MISSING_HOST=Missing host {0}. + +#Conversion messages +ECLIPSE_CONVERTER_ERROR_CONVERTING=Error converting plugin at {0}. +ECLIPSE_CONVERTER_ERROR_CREATING_BUNDLE_MANIFEST=Error creating bundle manifest file for {0} at {1}. +ECLIPSE_CONVERTER_ERROR_PARSING_PLUGIN_MANIFEST=Error parsing plugin manifest file {0} at {1}. +ECLIPSE_CONVERTER_MISSING_ATTRIBUTE=Error parsing {0} manifest. Missing attribute \"{1}\" in element \"{2}\". +ECLIPSE_CONVERTER_PLUGIN_LIBRARY_IGNORED=Plugin library {0} ignored when creating manifest for {1}. +ECLIPSE_CONVERTER_NO_SAX_FACTORY=No SAX factory parser has been found. +ECLIPSE_CONVERTER_PARSE_UNKNOWNTOP_ELEMENT = Unknown element \"{0}\", found at the top level, ignored. +ECLIPSE_CONVERTER_FILENOTFOUND = Could not find a plugin.xml or a fragment.xml in {0}. +parse_error=Error parsing manifest: {0} +parse_errorNameLineColumn=Error parsing manifest at \"{0}\" line \"{1}\" column \"{2}\": {3} + +#Classloader messages +ECLIPSE_CLASSLOADER_CANNOT_GET_HEADERS=Error loading bundle manifest for {0}. Using default auto-activation settings. +ECLIPSE_CLASSLOADER_CONCURRENT_STARTUP=While loading class "{1}", thread "{0}" timed out waiting ({4}ms) for thread "{2}" to finish starting bundle "{3}". To avoid deadlock, thread "{0}" is proceeding but "{1}" may not be fully initialized. +ECLIPSE_CLASSLOADER_ACTIVATION=An error occurred while automatically activating bundle {0} ({1}). +ECLIPSE_CLASSLOADER_GENERATED_EXCEPTION=Generated exception. +ECLIPSE_CLASSLOADER_ALREADY_STOPPED= The class \"{0}\" cannot be loaded because the system is shutting down and the plug-in \"{1}\" has already been stopped. +ECLIPSE_CLASSLOADER_CANNOT_SET_CONTEXTFINDER=The context finder has not been installed. + +#CachedManifest messages +ECLIPSE_CACHEDMANIFEST_UNEXPECTED_EXCEPTION=Unexpected exception occurred loading manifest for bundle at the location: {0}. + +#BundleStopper messages +ECLIPSE_BUNDLESTOPPER_CYCLES_FOUND=Info: cycle(s) found while stopping bundles: {0}. +ECLIPSE_BUNDLESTOPPER_ERROR_STOPPING_BUNDLE=Error while stopping \"{0}\". + +#Location message +ECLIPSE_CANNOT_CHANGE_LOCATION = Cannot change the location once it is set. + +#NL Problem +error_badNL=Bad value: \"{0}\" for NL. Using system default. + +#FileMananger messages +fileManager_cannotLock = Unable to create lock manager. +fileManager_couldNotSave = Could not save file table. +fileManager_updateFailed = File update failed on one or more files. +fileManager_illegalInReadOnlyMode = Cannot perform operation while in read-only mode. +fileManager_notOpen = Manager is not opened. + +#Location messages +location_cannotLockNIO = An error occurred while locking file \"{0}\": \"{1}\". A common reason is that the file system or Runtime Environment does not support file locking for that location. Please choose a different location, or disable file locking passing {2} as a VM argument. +location_cannotLock = An error occurred while locking file \"{0}\". diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMsg.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMsg.java new file mode 100644 index 000000000..1c2db825a --- /dev/null +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/EclipseAdaptorMsg.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2004, 2005 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.core.runtime.internal.adaptor; + +import java.util.Date; +import org.eclipse.osgi.service.resolver.*; +import org.eclipse.osgi.util.NLS; + +public class EclipseAdaptorMsg extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.core.runtime.internal.adaptor.EclipseAdaptorMessages"; //$NON-NLS-1$ + + public static String ECLIPSE_MISSING_IMPORTED_PACKAGE; + public static String ECLIPSE_MISSING_OPTIONAL_REQUIRED_BUNDLE; + public static String ECLIPSE_MISSING_REQUIRED_BUNDLE; + public static String ECLIPSE_MISSING_HOST; + public static String ECLIPSE_CANNOT_CHANGE_LOCATION; + public static String ECLIPSE_BUNDLESTOPPER_CYCLES_FOUND; + public static String ECLIPSE_BUNDLESTOPPER_ERROR_STOPPING_BUNDLE; + public static String ECLIPSE_CACHEDMANIFEST_UNEXPECTED_EXCEPTION; + + public static String fileManager_cannotLock; + public static String fileManager_couldNotSave; + public static String fileManager_updateFailed; + public static String fileManager_illegalInReadOnlyMode; + public static String fileManager_notOpen; + + public static String ECLIPSE_ADAPTOR_ERROR_XML_SERVICE; + public static String ECLIPSE_ADAPTOR_RUNTIME_ERROR; + public static String ECLIPSE_ADAPTOR_EXITING; + + public static String ECLIPSE_DATA_MANIFEST_NOT_FOUND; + public static String ECLIPSE_CONVERTER_ERROR_CONVERTING; + public static String ECLIPSE_DATA_ERROR_READING_MANIFEST; + public static String ECLIPSE_CLASSLOADER_CANNOT_GET_HEADERS; + + public static String ECLIPSE_CLASSLOADER_CONCURRENT_STARTUP; + public static String ECLIPSE_CLASSLOADER_ACTIVATION; + public static String ECLIPSE_CLASSLOADER_ALREADY_STOPPED; + public static String ECLIPSE_CLASSLOADER_GENERATED_EXCEPTION; + public static String ECLIPSE_CLASSLOADER_CANNOT_SET_CONTEXTFINDER; + + public static String ECLIPSE_CONSOLE_COMMANDS_HEADER; + public static String ECLIPSE_CONSOLE_HELP_DIAG_COMMAND_DESCRIPTION; + public static String ECLIPSE_CONSOLE_HELP_ACTIVE_COMMAND_DESCRIPTION; + public static String ECLIPSE_CONSOLE_HELP_GETPROP_COMMAND_DESCRIPTION; + public static String ECLIPSE_CONSOLE_NO_BUNDLE_SPECIFIED_ERROR; + public static String ECLIPSE_CONSOLE_NO_CONSTRAINTS_NO_PLATFORM_ADMIN_MESSAGE; + public static String ECLIPSE_CONSOLE_CANNOT_FIND_BUNDLE_ERROR; + public static String ECLIPSE_CONSOLE_NO_CONSTRAINTS; + public static String ECLIPSE_CONSOLE_OTHER_VERSION; + public static String ECLIPSE_CONSOLE_BUNDLES_ACTIVE; + + public static String ECLIPSE_STARTUP_ALREADY_RUNNING; + public static String ECLIPSE_STARTUP_STARTUP_ERROR; + public static String ECLIPSE_STARTUP_SHUTDOWN_ERROR; + public static String ECLIPSE_STARTUP_ERROR_CHECK_LOG; + public static String ECLIPSE_STARTUP_NOT_RUNNING; + public static String ECLIPSE_STARTUP_ERROR_NO_APPLICATION; + public static String ECLIPSE_STARTUP_ROOTS_NOT_RESOLVED; + public static String ECLIPSE_STARTUP_ALL_NOT_RESOLVED; + public static String ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_ACTIVE; + public static String ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED; + public static String ECLIPSE_STARTUP_BUNDLE_NOT_FOUND; + public static String ECLIPSE_STARTUP_INVALID_PORT; + public static String ECLIPSE_STARTUP_FAILED_FIND; + public static String ECLIPSE_STARTUP_FAILED_UNINSTALL; + public static String ECLIPSE_STARTUP_FAILED_INSTALL; + public static String ECLIPSE_STARTUP_FAILED_START; + public static String ECLIPSE_STARTUP_APP_ERROR; + public static String ECLIPSE_STARTUP_FILEMANAGER_OPEN_ERROR; + public static String ECLIPSE_STARTUP_PROPS_NOT_SET; + + public static String error_badNL; + + public static String location_cannotLock; + public static String location_cannotLockNIO; + + public static String ECLIPSE_CONVERTER_FILENOTFOUND; + public static String ECLIPSE_CONVERTER_ERROR_CREATING_BUNDLE_MANIFEST; + public static String ECLIPSE_CONVERTER_PLUGIN_LIBRARY_IGNORED; + + public static String ECLIPSE_CONVERTER_ERROR_PARSING_PLUGIN_MANIFEST; + public static String ECLIPSE_CONVERTER_MISSING_ATTRIBUTE; + public static String parse_error; + public static String parse_errorNameLineColumn; + + public static String ECLIPSE_CONVERTER_NO_SAX_FACTORY; + public static String ECLIPSE_CONVERTER_PARSE_UNKNOWNTOP_ELEMENT; + + public static final String NEW_LINE = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + + static { + // initialize resource bundles + NLS.initializeMessages(BUNDLE_NAME, EclipseAdaptorMsg.class); + } + + public static String getResolutionFailureMessage(VersionConstraint unsatisfied) { + if (unsatisfied.isResolved()) + throw new IllegalArgumentException(); + if (unsatisfied instanceof ImportPackageSpecification) + return NLS.bind(ECLIPSE_MISSING_IMPORTED_PACKAGE, toString(unsatisfied)); + else if (unsatisfied instanceof BundleSpecification) + if (((BundleSpecification) unsatisfied).isOptional()) + return NLS.bind(ECLIPSE_MISSING_OPTIONAL_REQUIRED_BUNDLE, toString(unsatisfied)); + else + return NLS.bind(ECLIPSE_MISSING_REQUIRED_BUNDLE, toString(unsatisfied)); + else + return NLS.bind(ECLIPSE_MISSING_HOST, toString(unsatisfied)); + } + + /** + * Print a debug message to the console. + * Pre-pend the message with the current date and the name of the current thread. + */ + public static void debug(String message) { + StringBuffer buffer = new StringBuffer(); + buffer.append(new Date(System.currentTimeMillis())); + buffer.append(" - ["); //$NON-NLS-1$ + buffer.append(Thread.currentThread().getName()); + buffer.append("] "); //$NON-NLS-1$ + buffer.append(message); + System.out.println(buffer.toString()); + } + + private static String toString(VersionConstraint constraint) { + org.eclipse.osgi.service.resolver.VersionRange versionRange = constraint.getVersionRange(); + if (versionRange == null) + return constraint.getName(); + return constraint.getName() + '_' + versionRange; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/Locker_JavaNio.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/Locker_JavaNio.java index ee8ce4914..6b7ed956b 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/Locker_JavaNio.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/core/runtime/internal/adaptor/Locker_JavaNio.java @@ -12,7 +12,6 @@ package org.eclipse.core.runtime.internal.adaptor; import java.io.*; import java.nio.channels.FileLock; -import org.eclipse.core.runtime.adaptor.EclipseAdaptorMsg; import org.eclipse.osgi.util.NLS; /** diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java index a03cc3e83..0321479b0 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFile.java @@ -501,6 +501,7 @@ public class ReliableFile { * Answers a boolean indicating whether or not the specified reliable file * exists on the underlying file system. This call only returns if a file * exists and not if the file contents are valid. + * @param file returns true if the specified reliable file exists; otherwise false is returned * * @return <code>true</code> if the specified reliable file exists, * <code>false</code> otherwise. @@ -573,6 +574,7 @@ public class ReliableFile { /** * Delete the specified reliable file on the underlying file system. + * @param deleteFile the reliable file to delete * * @return <code>true</code> if the specified reliable file was deleted, * <code>false</code> otherwise. diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java index c817fda06..e1dffe8a4 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileInputStream.java @@ -120,6 +120,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default FilterInputStream method. + * @see FilterInputStream#read(byte[], int, int) */ public synchronized int read(byte b[], int off, int len) throws IOException { if (readPos >= length) { @@ -138,6 +139,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default FilterInputStream method. + * @see FilterInputStream#read(byte[]) */ public synchronized int read(byte b[]) throws IOException { return read(b, 0, b.length); @@ -145,6 +147,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default FilterInputStream method. + * @see FilterInputStream#read() */ public synchronized int read() throws IOException { if (readPos >= length) { @@ -160,6 +163,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default available method. + * @see FilterInputStream#available() */ public synchronized int available() throws IOException { if (readPos < length) // just in case @@ -169,6 +173,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default skip method. + * @see FilterInputStream#skip(long) */ public synchronized long skip(long n) throws IOException { long len = super.skip(n); @@ -180,6 +185,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default markSupported method. + * @see FilterInputStream#markSupported() */ public boolean markSupported() { return false; @@ -187,6 +193,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default mark method. + * @see FilterInputStream#mark(int) */ public void mark(int readlimit) { //ignore @@ -194,6 +201,7 @@ public class ReliableFileInputStream extends FilterInputStream { /** * Override default reset method. + * @see FilterInputStream#reset() */ public void reset() throws IOException { throw new IOException("reset not supported."); //$NON-NLS-1$ diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java index a67f88f54..3c2a3a099 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/framework/internal/reliablefile/ReliableFileOutputStream.java @@ -142,6 +142,7 @@ public class ReliableFileOutputStream extends FilterOutputStream { /** * Override default FilterOutputStream method. + * @see FilterOutputStream#write(byte[]) */ public void write(byte[] b) throws IOException { this.write(b, 0, b.length); @@ -149,6 +150,7 @@ public class ReliableFileOutputStream extends FilterOutputStream { /** * Override default FilterOutputStream method. + * @see FilterOutputStream#write(byte[], int, int) */ public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); @@ -157,6 +159,7 @@ public class ReliableFileOutputStream extends FilterOutputStream { /** * Override default FilterOutputStream method. + * @see FilterOutputStream#write(int) */ public void write(int b) throws IOException { out.write(b); diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/service/datalocation/Location.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/service/datalocation/Location.java index b8fba576e..6b1ebe3a9 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/service/datalocation/Location.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/service/datalocation/Location.java @@ -128,6 +128,7 @@ public interface Location { * Locking a location is advisory only. That is, it does not prevent other applications from * modifying the same location * </p> + * @return true if the lock could be acquired; otherwise false is returned * * @exception IOException if there was an unexpected problem while acquiring the lock */ diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/service/localization/BundleLocalization.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/service/localization/BundleLocalization.java index 7e4fa4586..2061517ba 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/service/localization/BundleLocalization.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/service/localization/BundleLocalization.java @@ -26,6 +26,8 @@ public interface BundleLocalization { /** * The getLocalization method gets a ResourceBundle object for the given * locale and bundle. + * @param bundle the bundle to get localization for + * @param locale the name of the locale to get * * @return A <code>ResourceBundle</code> object for the given bundle and locale. * If <code>null</code> is passed for the locale parameter, the default locale is used. diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/storagemanager/ManagedOutputStream.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/storagemanager/ManagedOutputStream.java index 7a3aaaf0c..4c4cf045d 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/storagemanager/ManagedOutputStream.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/storagemanager/ManagedOutputStream.java @@ -46,6 +46,7 @@ public final class ManagedOutputStream extends FilterOutputStream { * a set returned by {@link StorageManager#getOutputStreamSet(String[])} then * the storage manager will only be updated with the new content after all * of the managed output streams in the set are closed successfully. + * @see FilterOutputStream#close() */ public void close() throws IOException { manager.closeOutputStream(this); diff --git a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/storagemanager/StorageManager.java b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/storagemanager/StorageManager.java index 1ab2e7901..09f973563 100644 --- a/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/storagemanager/StorageManager.java +++ b/bundles/org.eclipse.osgi/supplement/src/org/eclipse/osgi/storagemanager/StorageManager.java @@ -12,9 +12,7 @@ package org.eclipse.osgi.storagemanager; import java.io.*; import java.util.*; -import org.eclipse.core.runtime.adaptor.EclipseAdaptorMsg; -import org.eclipse.core.runtime.internal.adaptor.BasicLocation; -import org.eclipse.core.runtime.internal.adaptor.Locker; +import org.eclipse.core.runtime.internal.adaptor.*; import org.eclipse.osgi.framework.internal.reliablefile.*; import org.eclipse.osgi.framework.util.SecureAction; @@ -459,6 +457,7 @@ public final class StorageManager { * Removes the given managed file from management by this storage manager. * * @param managedFile the managed file to remove + * @throws IOException if an error occured removing the managed file */ public void remove(String managedFile) throws IOException { if (!open) @@ -686,6 +685,7 @@ public final class StorageManager { * This methods opens the storage manager. * This method must be called before any operation on the storage manager. * @param wait indicates if the open operation must wait in case of contention on the lock file. + * @throws IOException if an error occured opening the storage manager */ public void open(boolean wait) throws IOException { if (openCleanup) |