Bug 567344 - Support registration of IAdapterFactory as OSGi Service

Change-Id: Ifcfcfea774134a1033b85b8919ac99daa6838257
Signed-off-by: Christoph Laeubrich <laeubi@laeubi-soft.de>
diff --git a/bundles/org.eclipse.equinox.common.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.common.tests/META-INF/MANIFEST.MF
index 788dbac..ae49a5e 100644
--- a/bundles/org.eclipse.equinox.common.tests/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.common.tests/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: Common Eclipse Runtime Tests
 Bundle-Vendor: Eclipse.org - Equinox
 Bundle-SymbolicName: org.eclipse.equinox.common.tests;singleton:=true
-Bundle-Version: 3.13.0.qualifier
+Bundle-Version: 3.14.0.qualifier
 Automatic-Module-Name: org.eclipse.equinox.common.tests
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Bundle-ActivationPolicy: lazy
diff --git a/bundles/org.eclipse.equinox.common.tests/pom.xml b/bundles/org.eclipse.equinox.common.tests/pom.xml
index c90237b..b616c3f 100644
--- a/bundles/org.eclipse.equinox.common.tests/pom.xml
+++ b/bundles/org.eclipse.equinox.common.tests/pom.xml
@@ -19,7 +19,7 @@
   </parent>
   <groupId>org.eclipse.equinox</groupId>
   <artifactId>org.eclipse.equinox.common.tests</artifactId>
-  <version>3.13.0-SNAPSHOT</version>
+  <version>3.14.0-SNAPSHOT</version>
   <packaging>eclipse-test-plugin</packaging>
   <properties>
     <testClass>org.eclipse.equinox.common.tests.AllTests</testClass>
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/IAdapterManagerServiceTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/IAdapterManagerServiceTest.java
index aae64bf..49edf54 100644
--- a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/IAdapterManagerServiceTest.java
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/IAdapterManagerServiceTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2018 IBM Corporation and others.
+ * Copyright (c) 2007, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM - Initial API and implementation
  *     Alexander Kurtakov <akurtako@redhat.com> - bug 458490
+ *     Christoph Laeubrich - Bug 567344
  *******************************************************************************/
 package org.eclipse.equinox.common.tests.adaptable;
 
@@ -18,12 +19,18 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.Hashtable;
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import org.eclipse.core.runtime.IAdapterFactory;
 import org.eclipse.core.runtime.IAdapterManager;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.util.tracker.ServiceTracker;
 
 /**
@@ -35,6 +42,7 @@
 public class IAdapterManagerServiceTest {
 	private static final String NON_EXISTING = "com.does.not.Exist";
 	private static final String TEST_ADAPTER = "org.eclipse.equinox.common.tests.adaptable.TestAdapter";
+	private static final String TEST_ADAPTER_OSGI = TestAdapter2.class.getName();
 
 	private static IAdapterManager manager;
 
@@ -49,6 +57,78 @@
 		adapterManagerTracker.open();
 		manager = adapterManagerTracker.getService();
 		adapterManagerTracker.close();
+
+	}
+
+	@Test
+	public void testAdaptersOSGiLazy() {
+		AtomicBoolean created = new AtomicBoolean();
+		AtomicBoolean unregistered = new AtomicBoolean();
+		TestAdaptable2 adaptable = new TestAdaptable2();
+		assertFalse("already present", manager.hasAdapter(adaptable, TEST_ADAPTER_OSGI));
+		BundleContext context = FrameworkUtil.getBundle(IAdapterManagerServiceTest.class).getBundleContext();
+		Hashtable<String, Object> properties = new Hashtable<>();
+		properties.put(IAdapterFactory.SERVICE_PROPERTY_ADAPTABLE_CLASS, TestAdaptable2.class.getName());
+		ServiceRegistration<?> registration = context.registerService(IAdapterFactory.class.getName(),
+				new ServiceFactory<IAdapterFactory>() {
+
+					@Override
+					public IAdapterFactory getService(Bundle bundle, ServiceRegistration<IAdapterFactory> r) {
+						created.set(true);
+						return new TestAdapterFactory2(TestAdapter2::new);
+					}
+
+					@Override
+					public void ungetService(Bundle bundle, ServiceRegistration<IAdapterFactory> r,
+							IAdapterFactory service) {
+						unregistered.set(true);
+					}
+				}, properties);
+		assertFalse(created.get());
+		Object result = manager.getAdapter(adaptable, TEST_ADAPTER_OSGI);
+		assertTrue("result is not of desired type", result instanceof TestAdapter2);
+		assertTrue(created.get());
+		registration.unregister();
+		assertFalse("manager is still present", manager.hasAdapter(adaptable, TEST_ADAPTER_OSGI));
+		assertTrue(unregistered.get());
+	}
+
+	@Test
+	public void testAdaptersOSGiLazyExt() {
+		AtomicBoolean created = new AtomicBoolean();
+		AtomicBoolean unregistered = new AtomicBoolean();
+		TestAdaptable2 adaptable = new TestAdaptable2();
+		assertFalse("already present", manager.hasAdapter(adaptable, TEST_ADAPTER_OSGI));
+		BundleContext context = FrameworkUtil.getBundle(IAdapterManagerServiceTest.class).getBundleContext();
+		Hashtable<String, Object> properties = new Hashtable<>();
+		properties.put(IAdapterFactory.SERVICE_PROPERTY_ADAPTABLE_CLASS, TestAdaptable2.class.getName());
+		properties.put(IAdapterFactory.SERVICE_PROPERTY_ADAPTER_NAMES, TestAdapter2.class.getName());
+		ServiceRegistration<?> registration = context.registerService(IAdapterFactory.class.getName(),
+				new ServiceFactory<IAdapterFactory>() {
+
+					@Override
+					public IAdapterFactory getService(Bundle bundle,
+							ServiceRegistration<IAdapterFactory> r) {
+						created.set(true);
+						return new TestAdapterFactory2(TestAdapter2::new);
+					}
+
+					@Override
+					public void ungetService(Bundle bundle, ServiceRegistration<IAdapterFactory> r,
+							IAdapterFactory service) {
+						unregistered.set(true);
+					}
+				}, properties);
+		assertTrue("manager is not present", manager.hasAdapter(adaptable, TEST_ADAPTER_OSGI));
+		Object result = manager.getAdapter(adaptable, TEST_ADAPTER_OSGI);
+		assertNull("result should be null", result);
+		assertFalse(created.get());
+		result = manager.loadAdapter(adaptable, TEST_ADAPTER_OSGI);
+		assertTrue("result is not of desired type", result instanceof TestAdapter2);
+		assertTrue(created.get());
+		registration.unregister();
+		assertFalse("manager is still present", manager.hasAdapter(adaptable, TEST_ADAPTER_OSGI));
+		assertTrue(unregistered.get());
 	}
 
 	/**
@@ -178,4 +258,5 @@
 		// request adapter that was unloaded
 		assertNull("1.4", manager.loadAdapter(adaptable, "java.lang.String"));
 	}
+
 }
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/TestAdaptable2.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/TestAdaptable2.java
new file mode 100644
index 0000000..88c7285
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/TestAdaptable2.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2020 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM - Initial API and implementation
+ *     Christoph Laeubrich - Bug 567344
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests.adaptable;
+
+import org.eclipse.core.runtime.PlatformObject;
+
+/**
+ * Used by IAdapterManagerTest
+ */
+public class TestAdaptable2 extends PlatformObject {
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/TestAdapter2.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/TestAdapter2.java
new file mode 100644
index 0000000..0d2652d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/TestAdapter2.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2020 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM - Initial API and implementation
+ *     Christoph Laeubrich - Bug 567344 
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests.adaptable;
+
+/**
+ * Used by IAdapterManagerTest
+ */
+public class TestAdapter2 {
+}
diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/TestAdapterFactory2.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/TestAdapterFactory2.java
new file mode 100644
index 0000000..c9c6977
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/adaptable/TestAdapterFactory2.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2020 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM - Initial API and implementation
+ *     Christoph Laeubrich - Bug 567344
+ *******************************************************************************/
+package org.eclipse.equinox.common.tests.adaptable;
+
+import java.util.function.Supplier;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.junit.Assert;
+
+/**
+ */
+public class TestAdapterFactory2 extends Assert implements IAdapterFactory {
+
+	private Supplier<TestAdapter2> supplier;
+
+	public TestAdapterFactory2(Supplier<TestAdapter2> supplier) {
+		this.supplier = supplier;
+	}
+
+	@Override
+	public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
+		assertTrue("Request for wrong adapter", adaptableObject instanceof TestAdaptable2);
+		return adapterType.cast(supplier.get());
+	}
+
+	@Override
+	public Class<?>[] getAdapterList() {
+		return new Class[] { TestAdapter2.class };
+	}
+}
diff --git a/bundles/org.eclipse.equinox.common/.settings/.api_filters b/bundles/org.eclipse.equinox.common/.settings/.api_filters
new file mode 100644
index 0000000..00f03e1
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common/.settings/.api_filters
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.equinox.common" version="2">
+    <resource path="src/org/eclipse/core/runtime/IAdapterFactory.java" type="org.eclipse.core.runtime.IAdapterFactory">
+        <filter id="403767336">
+            <message_arguments>
+                <message_argument value="org.eclipse.core.runtime.IAdapterFactory"/>
+                <message_argument value="SERVICE_PROPERTY_ADAPTABLE_CLASS"/>
+            </message_arguments>
+        </filter>
+        <filter id="403767336">
+            <message_arguments>
+                <message_argument value="org.eclipse.core.runtime.IAdapterFactory"/>
+                <message_argument value="SERVICE_PROPERTY_ADAPTER_NAMES"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
\ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF
index 046bb34..c669ffd 100644
--- a/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF
@@ -14,7 +14,7 @@
    org.eclipse.core.runtime.compatibility,
    org.eclipse.core.filesystem,
    org.eclipse.equinox.security",
- org.eclipse.core.runtime;common=split;version="3.6.0";mandatory:=common,
+ org.eclipse.core.runtime;common=split;version="3.7.0";mandatory:=common,
  org.eclipse.core.text;version="3.13.0",
  org.eclipse.equinox.events;version="1.0.0"
 Bundle-Vendor: %providerName
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java
index d8f240c..7b9debb 100644
--- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java
+++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/Activator.java
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Sergey Prigogin (Google) - use parameterized types (bug 442021)
+ *     Christoph Laeubrich - Bug 567344 - Support registration of IAdapterFactory as OSGi Service
  *******************************************************************************/
 package org.eclipse.core.internal.runtime;
 
@@ -18,8 +19,7 @@
 import java.util.*;
 import org.eclipse.core.internal.boot.PlatformURLBaseConnection;
 import org.eclipse.core.internal.boot.PlatformURLHandler;
-import org.eclipse.core.runtime.IAdapterManager;
-import org.eclipse.core.runtime.ServiceCaller;
+import org.eclipse.core.runtime.*;
 import org.eclipse.equinox.log.ExtendedLogReaderService;
 import org.eclipse.equinox.log.ExtendedLogService;
 import org.eclipse.osgi.framework.log.FrameworkLog;
@@ -62,6 +62,8 @@
 
 	private ServiceRegistration<DebugOptionsListener> debugRegistration;
 
+	private ServiceTracker<IAdapterFactory, ?> adapterFactoryTracker;
+
 	/*
 	 * Returns the singleton for this Activator. Callers should be aware that
 	 * this will return null if the bundle is not active.
@@ -84,6 +86,8 @@
 		Hashtable<String, String> properties = new Hashtable<>(2);
 		properties.put(DebugOptions.LISTENER_SYMBOLICNAME, PLUGIN_ID);
 		debugRegistration = context.registerService(DebugOptionsListener.class, TracingOptions.DEBUG_OPTIONS_LISTENER, properties);
+		adapterFactoryTracker = new ServiceTracker<>(context, IAdapterFactory.class, new AdapterFactoryBridge(bundleContext));
+		adapterFactoryTracker.open();
 	}
 
 	private PlatformLogWriter getPlatformWriter(BundleContext context) {
@@ -208,6 +212,9 @@
 
 	@Override
 	public void stop(BundleContext context) throws Exception {
+		if (adapterFactoryTracker != null) {
+			adapterFactoryTracker.close();
+		}
 		closeURLTrackerServices();
 		if (platformURLConverterService != null) {
 			platformURLConverterService.unregister();
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/AdapterFactoryBridge.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/AdapterFactoryBridge.java
new file mode 100644
index 0000000..edaa20f
--- /dev/null
+++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/AdapterFactoryBridge.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Christoph Laeubrich and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors:
+ *     Christoph Laeubrich - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.core.internal.runtime;
+
+import java.util.Collection;
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.core.runtime.IAdapterManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/**
+ * Acts as abridge between {@link IAdapterManager} services registered in the OSGi-Service-Registry and AdapterManager
+ *
+ */
+public class AdapterFactoryBridge implements ServiceTrackerCustomizer<IAdapterFactory, AdapterFactoryBridge.LazyAdapterFactory> {
+	private BundleContext bundleContext;
+
+	public AdapterFactoryBridge(BundleContext bundleContext) {
+		this.bundleContext = bundleContext;
+	}
+
+	@Override
+	public LazyAdapterFactory addingService(ServiceReference<IAdapterFactory> reference) {
+		String[] adaptableClasses = getMultiProperty(reference, IAdapterFactory.SERVICE_PROPERTY_ADAPTABLE_CLASS);
+		String[] adapterNames = getMultiProperty(reference, IAdapterFactory.SERVICE_PROPERTY_ADAPTER_NAMES);
+		LazyAdapterFactory proxy;
+		if (adapterNames.length == 0 && reference.getProperty(IAdapterFactory.SERVICE_PROPERTY_ADAPTER_NAMES) == null) {
+			proxy = new LazyAdapterFactory(reference, bundleContext);
+		} else {
+			proxy = new LazyAdapterFactoryExtServiceProxy(adapterNames, reference, bundleContext);
+		}
+		AdapterManager manager = AdapterManager.getDefault();
+		for (String adaptableClass : adaptableClasses) {
+			manager.registerFactory(proxy, adaptableClass);
+		}
+		manager.flushLookup();
+		return proxy;
+	}
+
+	private static String[] getMultiProperty(ServiceReference<?> reference, String propertyName) {
+		Object property = reference.getProperty(propertyName);
+		if (property instanceof String) {
+			String string = (String) property;
+			if (string.length() > 0) {
+				return new String[] {string};
+			}
+		} else if (property instanceof String[]) {
+			return (String[]) property;
+		} else if (property instanceof Collection<?>) {
+			Collection<?> collection = (Collection<?>) property;
+			return collection.stream().filter(String.class::isInstance).map(String.class::cast).toArray(String[]::new);
+		}
+		return new String[0];
+	}
+
+	@Override
+	public void modifiedService(ServiceReference<IAdapterFactory> reference, LazyAdapterFactory proxy) {
+		String[] adaptableClasses = getMultiProperty(reference, IAdapterFactory.SERVICE_PROPERTY_ADAPTABLE_CLASS);
+		AdapterManager manager = AdapterManager.getDefault();
+		manager.unregisterAdapters(proxy);
+		if (proxy instanceof LazyAdapterFactoryExtServiceProxy) {
+			LazyAdapterFactoryExtServiceProxy lazy = (LazyAdapterFactoryExtServiceProxy) proxy;
+			lazy.adapterNames = getMultiProperty(reference, IAdapterFactory.SERVICE_PROPERTY_ADAPTER_NAMES);
+		}
+		for (String adaptableClass : adaptableClasses) {
+			manager.registerFactory(proxy, adaptableClass);
+		}
+		manager.flushLookup();
+	}
+
+	@Override
+	public void removedService(ServiceReference<IAdapterFactory> reference, LazyAdapterFactory proxy) {
+		AdapterManager manager = AdapterManager.getDefault();
+		manager.unregisterAdapters(proxy);
+		proxy.dispose();
+	}
+
+	public static class LazyAdapterFactory implements IAdapterFactory {
+
+		IAdapterFactory service;
+		volatile boolean disposed;
+		private final ServiceReference<IAdapterFactory> reference;
+		private final BundleContext bundleContext;
+
+		LazyAdapterFactory(ServiceReference<IAdapterFactory> reference, BundleContext bundleContext) {
+			this.reference = reference;
+			this.bundleContext = bundleContext;
+		}
+
+		@Override
+		public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
+			if (!disposed) {
+				IAdapterFactory factory = getFactoryService();
+				if (factory != null) {
+					return factory.getAdapter(adaptableObject, adapterType);
+				}
+			}
+			return null;
+		}
+
+		@Override
+		public Class<?>[] getAdapterList() {
+			if (!disposed) {
+				IAdapterFactory factory = getFactoryService();
+				if (factory != null) {
+					return factory.getAdapterList();
+				}
+			}
+			return new Class<?>[0];
+		}
+
+		synchronized IAdapterFactory getFactoryService() {
+			if (service == null && !disposed) {
+				service = bundleContext.getService(reference);
+			}
+			return service;
+		}
+
+		synchronized void dispose() {
+			disposed = true;
+			if (service != null) {
+				service = null;
+				bundleContext.ungetService(reference);
+			}
+		}
+
+	}
+
+	private static final class LazyAdapterFactoryExtServiceProxy extends LazyAdapterFactory implements IAdapterFactoryExt {
+
+		volatile String[] adapterNames;
+
+		LazyAdapterFactoryExtServiceProxy(String[] adapterNames, ServiceReference<IAdapterFactory> reference, BundleContext bundleContext) {
+			super(reference, bundleContext);
+			this.adapterNames = adapterNames;
+		}
+
+		@Override
+		public synchronized IAdapterFactory loadFactory(boolean force) {
+			if (force) {
+				return getFactoryService();
+			}
+			return service;
+		}
+
+		@Override
+		public String[] getAdapterNames() {
+			return adapterNames.clone();
+		}
+
+	}
+
+}
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/IAdapterFactory.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/IAdapterFactory.java
index 8648625..a61a8d5 100644
--- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/IAdapterFactory.java
+++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/IAdapterFactory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Sergey Prigogin (Google) - use parameterized types (bug 442021)
+ *     Christoph Laeubrich - Bug 567344 - Support registration of IAdapterFactory as OSGi Service
  *******************************************************************************/
 package org.eclipse.core.runtime;
 
@@ -28,6 +29,19 @@
  * @see IAdaptable
  */
 public interface IAdapterFactory {
+
+	/**
+	 * Service property to use when registering a factory as OSGi-service to declare the adaptable class type, this is a multi-string-property, if more than one is given the factory will be register multiple times
+	 * @since 3.14
+	 */
+	static final String SERVICE_PROPERTY_ADAPTABLE_CLASS = "adaptableClass"; //$NON-NLS-1$
+
+	/**
+	 * Optional service property to use when registering a factory as OSGi-service to declare the possible adapter types. If the property is given, the service is only queried when actually required, this is a multi-string-property.
+	 * @since 3.14
+	 */
+	static final String SERVICE_PROPERTY_ADAPTER_NAMES = "adapterNames"; //$NON-NLS-1$
+
 	/**
 	 * Returns an object which is an instance of the given class
 	 * associated with the given object. Returns <code>null</code> if
diff --git a/bundles/org.eclipse.equinox.registry/.settings/.api_filters b/bundles/org.eclipse.equinox.registry/.settings/.api_filters
new file mode 100644
index 0000000..93dc09e
--- /dev/null
+++ b/bundles/org.eclipse.equinox.registry/.settings/.api_filters
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.equinox.registry" version="2">
+    <resource path="META-INF/MANIFEST.MF">
+        <filter id="926941240">
+            <message_arguments>
+                <message_argument value="3.10.0"/>
+                <message_argument value="3.9.0"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/bundles/org.eclipse.equinox.registry/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.registry/META-INF/MANIFEST.MF
index e2b2473..4057e65 100644
--- a/bundles/org.eclipse.equinox.registry/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.registry/META-INF/MANIFEST.MF
@@ -2,16 +2,16 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.equinox.registry;singleton:=true
-Bundle-Version: 3.9.100.qualifier
+Bundle-Version: 3.10.0.qualifier
 Bundle-Localization: plugin
 Export-Package: org.eclipse.core.internal.adapter;x-internal:=true,
  org.eclipse.core.internal.registry;x-friends:="org.eclipse.core.runtime",
  org.eclipse.core.internal.registry.osgi;x-friends:="org.eclipse.core.runtime",
  org.eclipse.core.internal.registry.spi;x-internal:=true,
- org.eclipse.core.runtime;registry=split;version="3.6.0";mandatory:=registry,
+ org.eclipse.core.runtime;registry=split;version="3.7.0";mandatory:=registry,
  org.eclipse.core.runtime.dynamichelpers;version="3.4.0",
  org.eclipse.core.runtime.spi;version="3.4.0"
-Require-Bundle: org.eclipse.equinox.common;bundle-version="[3.13.0,4.0.0)"
+Require-Bundle: org.eclipse.equinox.common;bundle-version="[3.14.0,4.0.0)"
 Bundle-Vendor: %providerName
 Bundle-Activator: org.eclipse.core.internal.registry.osgi.Activator
 Import-Package: javax.xml.parsers,
diff --git a/bundles/org.eclipse.equinox.registry/pom.xml b/bundles/org.eclipse.equinox.registry/pom.xml
index 755defa..207729c 100644
--- a/bundles/org.eclipse.equinox.registry/pom.xml
+++ b/bundles/org.eclipse.equinox.registry/pom.xml
@@ -19,6 +19,6 @@
   </parent>
   <groupId>org.eclipse.equinox</groupId>
   <artifactId>org.eclipse.equinox.registry</artifactId>
-  <version>3.9.100-SNAPSHOT</version>
+  <version>3.10.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>