diff --git a/plugins/org.eclipse.emf.common/src/org/eclipse/emf/common/EMFPlugin.java b/plugins/org.eclipse.emf.common/src/org/eclipse/emf/common/EMFPlugin.java
index 1fad5d4e0..d513d16cb 100644
--- a/plugins/org.eclipse.emf.common/src/org/eclipse/emf/common/EMFPlugin.java
+++ b/plugins/org.eclipse.emf.common/src/org/eclipse/emf/common/EMFPlugin.java
@@ -82,6 +82,9 @@ public abstract class EMFPlugin extends DelegatingResourceLocator implements Res
boolean result = false;
try
{
+ // With this we make sure, that we are really in a proper Eclipse Environment with everything we need.
+ // Some supplements pretend that the Platform is running, but don't provide a ExtensionRegistry.
+ FrameworkUtil.getBundle(EMFPlugin.class).loadClass("org.eclipse.core.runtime.IRegistryChangeListener");
result = Platform.isRunning();
}
catch (Throwable exception)
diff --git a/plugins/org.eclipse.emf.ecore/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.ecore/META-INF/MANIFEST.MF
index 23079f604..e87ce86c9 100644
--- a/plugins/org.eclipse.emf.ecore/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.ecore/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.emf.ecore;singleton:=true
-Bundle-Version: 2.38.0.qualifier
+Bundle-Version: 2.39.0.qualifier
Bundle-ClassPath: .
Bundle-Activator: org.eclipse.emf.ecore.plugin.EcorePlugin$Implementation$Activator
Bundle-Vendor: %providerName
diff --git a/plugins/org.eclipse.emf.ecore/pom.xml b/plugins/org.eclipse.emf.ecore/pom.xml
index bf375057b..7fdd436ff 100644
--- a/plugins/org.eclipse.emf.ecore/pom.xml
+++ b/plugins/org.eclipse.emf.ecore/pom.xml
@@ -12,7 +12,7 @@
org.eclipse.emf
org.eclipse.emf.ecore
- 2.38.0-SNAPSHOT
+ 2.39.0-SNAPSHOT
eclipse-plugin
diff --git a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/EcorePlugin.java b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/EcorePlugin.java
index 2b5d3ba9e..edfb873bb 100644
--- a/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/EcorePlugin.java
+++ b/plugins/org.eclipse.emf.ecore/src/org/eclipse/emf/ecore/plugin/EcorePlugin.java
@@ -20,6 +20,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
@@ -27,6 +29,8 @@
import java.util.Map;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
@@ -52,11 +56,19 @@
import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
+import org.eclipse.emf.ecore.EFactory;
import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
@@ -69,6 +81,11 @@ public class EcorePlugin extends EMFPlugin
* The singleton instance of the plugin.
*/
public static final EcorePlugin INSTANCE = new EcorePlugin();
+
+ /**
+ * Feature toggle to enable OSGi ServiceTracker to replace {@link EPackage.Registry} with a registered Service
+ */
+ public static boolean USE_OSGI_SERVICE_AS_EPACKAGE_REGISTRY = Boolean.getBoolean("org.eclipse.emf.ecore.EPackage.Registry.OSGI_SERVICE");
/**
* Creates the singleton instance.
@@ -586,13 +603,18 @@ public static Map getEPackageNsURIToDynamicModelLocationMap(boolean
*/
static public class Implementation extends EclipsePlugin
{
- /**
+
+
+ private PlainOSGiBundleActivator plainOSGiBundleActivator;
+
+ /**
* Creates the singleton instance.
*/
public Implementation()
{
super();
plugin = this;
+ plainOSGiBundleActivator = new PlainOSGiBundleActivator();
}
/**
@@ -657,9 +679,61 @@ public void start(BundleContext context) throws Exception
{
super.start(context);
ExtensionProcessor.internalProcessExtensions();
-
+ if(plainOSGiBundleActivator != null)
+ {
+ plainOSGiBundleActivator.start(context);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ if(plainOSGiBundleActivator != null)
+ {
+ plainOSGiBundleActivator.stop(context);
+ }
}
+ /**
+ * In Case we are not running in Eclipse, this BundleActivator will be used
+ * @since 2.40
+ */
+ public static class PlainOSGiBundleActivator implements BundleActivator {
+
+ private ServiceTracker osgiEpackageRegistryTracker = null;
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public void start(BundleContext context) throws Exception {
+ if(getDefaultRegistryImplementation() != null && getDefaultRegistryImplementation() instanceof OSGiDelegatEPackageRegistry)
+ {
+ osgiEpackageRegistryTracker = new ServiceTracker<>(context, OSGiDelegatEPackageRegistry.FILTER, (ServiceTrackerCustomizer) getDefaultRegistryImplementation());
+ osgiEpackageRegistryTracker.open();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ if(osgiEpackageRegistryTracker != null)
+ {
+ osgiEpackageRegistryTracker.close();
+ }
+ }
+
+ }
+
/**
* @since 2.10
*/
@@ -668,7 +742,14 @@ public static final class Activator extends EMFPlugin.OSGiDelegatingBundleActiva
@Override
protected BundleActivator createBundle()
{
- return new Implementation();
+ if(IS_ECLIPSE_RUNNING)
+ {
+ return new Implementation();
+ } else
+ {
+ // If we are running in OSGi but not in Eclipse
+ return new PlainOSGiBundleActivator();
+ }
}
}
}
@@ -1098,6 +1179,11 @@ public String getSymbolicName()
*/
public static EPackage.Registry getDefaultRegistryImplementation()
{
+ if(defaultRegistryImplementation == null && EMFPlugin.IS_OSGI_RUNNING && USE_OSGI_SERVICE_AS_EPACKAGE_REGISTRY)
+ {
+ OSGiDelegatEPackageRegistry delegatorRegsitry = new OSGiDelegatEPackageRegistry();
+ defaultRegistryImplementation = delegatorRegsitry;
+ }
return defaultRegistryImplementation;
}
@@ -1309,4 +1395,412 @@ private static void computeModels(Map pluginMap, Map nsUR
* Since 2.14
*/
public static final String ANNOTATION_VALIDATOR_PPID = "annotation_validator";
+
+ /**
+ * A {@link Registry} that tries to look for a service as a global Registry. Due
+ * to the dynamic nature of OSGi Services and the static nature of the default
+ * {@link Registry} of {@link Registry#INSTANCE} it provides an internal backup.
+ * Which is used until the service comes around. All write operations will be
+ * stored with the backup as well, so it can take up its role, when the service
+ * goes away. When a suitable Service comes around, all statically added
+ * {@link EPackage}s will be added to the incoming Registry.
+ *
+ * Only {@link Registry} Services with the property
+ * "emf.default.epackage.registry=true" will be considered. If multiple match,
+ * the one with the highest service rank or if non is present, the first one
+ * wins.
+ */
+ private static class OSGiDelegatEPackageRegistry implements Registry, ServiceTrackerCustomizer {
+
+ public static Filter FILTER = null;
+ static {
+ try {
+ FILTER = FrameworkUtil.createFilter(
+ "(&(" + Constants.OBJECTCLASS + "=" + Registry.class.getName() + ")(emf.default.epackage.registry=true))");
+ } catch (Exception e) {
+ // Must not happen
+ }
+ }
+
+ private final Registry backup = new EPackageRegistryImpl();
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+ private final List> knownReferences = new ArrayList<>();
+
+ private ServiceReference currentDelegateRef = null;
+ private Registry delegate = null;
+
+ private BundleContext context;
+
+ /**
+ * Sets the BundleContext to use. Must be set before the Servicetracker is
+ * opened.
+ *
+ * @param context the context to set
+ */
+ public BundleContext getBundleContext() {
+ if (context == null) {
+ context = FrameworkUtil.getBundle(getClass()).getBundleContext();
+ }
+ return this.context;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#size()
+ */
+ @Override
+ public int size() {
+ lock.readLock().lock();
+ try {
+ if (delegate == null) {
+ return backup.size();
+ } else {
+ return delegate.size();
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#isEmpty()
+ */
+ @Override
+ public boolean isEmpty() {
+ lock.readLock().lock();
+ try {
+ if (delegate == null) {
+ return backup.isEmpty();
+ } else {
+ return delegate.isEmpty();
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#containsKey(java.lang.Object)
+ */
+ @Override
+ public boolean containsKey(Object key) {
+ lock.readLock().lock();
+ try {
+ if (delegate == null) {
+ return backup.containsKey(key);
+ } else {
+ return delegate.containsKey(key);
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#containsValue(java.lang.Object)
+ */
+ @Override
+ public boolean containsValue(Object value) {
+ lock.readLock().lock();
+ try {
+ if (delegate == null) {
+ return backup.containsValue(value);
+ } else {
+ return delegate.containsValue(value);
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#get(java.lang.Object)
+ */
+ @Override
+ public Object get(Object key) {
+ lock.readLock().lock();
+ try {
+ if (delegate == null) {
+ return backup.get(key);
+ } else {
+ return delegate.get(key);
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#put(java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public Object put(String key, Object value) {
+ lock.readLock().lock();
+ try {
+ if (delegate != null) {
+ backup.put(key, value);
+ return delegate.put(key, value);
+ }
+ return backup.put(key, value);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#remove(java.lang.Object)
+ */
+ @Override
+ public Object remove(Object key) {
+ lock.readLock().lock();
+ try {
+ if (delegate != null) {
+ backup.remove(key);
+ return delegate.remove(key);
+ }
+ return backup.remove(key);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#putAll(java.util.Map)
+ */
+ @Override
+ public void putAll(Map extends String, ? extends Object> m) {
+ lock.readLock().lock();
+ try {
+ if (delegate == null) {
+ backup.putAll(m);
+ } else {
+ delegate.putAll(m);
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#clear()
+ */
+ @Override
+ public void clear() {
+ lock.readLock().lock();
+ try {
+ if (delegate == null) {
+ backup.clear();
+ } else {
+ delegate.clear();
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#keySet()
+ */
+ @Override
+ public Set keySet() {
+ lock.readLock().lock();
+ try {
+ if (delegate == null) {
+ return backup.keySet();
+ } else {
+ return delegate.keySet();
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.Map#values()
+ */
+ @Override
+ public Collection