Bug 513377 - TranslationObjectSupplier leaks IRequestor

Change-Id: I62e817009b98569152bfa5dd2fa6a7ee17acc8e7
Signed-off-by: Dirk Fauth <dirk.fauth@googlemail.com>
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/MANIFEST.MF
index cec3c74..d6656d3 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/META-INF/MANIFEST.MF
@@ -8,6 +8,7 @@
 Require-Capability: osgi.extender;
   filter:="(&(osgi.extender=osgi.component)(version>=1.3)(!(version>=2.0)))"
 Import-Package: org.eclipse.core.runtime.preferences;version="3.3.0",
+ org.eclipse.e4.core.contexts;version="1.6.0",
  org.eclipse.e4.core.di,
  org.eclipse.e4.core.di.annotations;version="1.6.0",
  org.eclipse.e4.core.di.extensions;version="0.15.0",
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.EventObjectSupplier.xml b/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.EventObjectSupplier.xml
index 5ccf9ef..c6bb656 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.EventObjectSupplier.xml
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.EventObjectSupplier.xml
@@ -1,8 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipse.e4.core.di.internal.extensions.EventObjectSupplier">
    <property name="dependency.injection.annotation" value="org.eclipse.e4.core.di.extensions.EventTopic"/>
+   <property name="event.topics" value="org/eclipse/e4/core/contexts/IEclipseContext/DISPOSE"/>
    <service>
       <provide interface="org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier"/>
+      <provide interface="org.osgi.service.event.EventHandler"/>
    </service>
    <reference bind="setEventAdmin" cardinality="1..1" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static"/>
    <implementation class="org.eclipse.e4.core.di.internal.extensions.EventObjectSupplier"/>
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.OSGiObjectSupplier.xml b/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.OSGiObjectSupplier.xml
index eb7903f..4b40b28 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.OSGiObjectSupplier.xml
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.OSGiObjectSupplier.xml
@@ -1,8 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" name="org.eclipse.e4.core.di.internal.extensions.OSGiObjectSupplier">
    <property name="dependency.injection.annotation" value="org.eclipse.e4.core.di.extensions.OSGiBundle"/>
+   <property name="event.topics" value="org/eclipse/e4/core/contexts/IEclipseContext/DISPOSE"/>
    <service>
       <provide interface="org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier"/>
+      <provide interface="org.osgi.service.event.EventHandler"/>
    </service>
    <implementation class="org.eclipse.e4.core.di.internal.extensions.OSGiObjectSupplier"/>
 </scr:component>
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier.xml b/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier.xml
index e08a6d8..8479ee0 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier.xml
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier.xml
@@ -1,8 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" deactivate="removeAllListeners" immediate="true" name="org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier">
    <property name="dependency.injection.annotation" value="org.eclipse.e4.core.di.extensions.Preference"/>
+   <property name="event.topics" value="org/eclipse/e4/core/contexts/IEclipseContext/DISPOSE"/>
    <service>
       <provide interface="org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier"/>
+      <provide interface="org.osgi.service.event.EventHandler"/>
    </service>
    <reference bind="setPreferencesService" cardinality="1..1" interface="org.eclipse.core.runtime.preferences.IPreferencesService" name="PreferencesService" policy="static"/>
    <implementation class="org.eclipse.e4.core.di.internal.extensions.PreferencesObjectSupplier"/>
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.ServiceSupplier.xml b/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.ServiceSupplier.xml
index 2ea4ba3..23b8d7f 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.ServiceSupplier.xml
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/OSGI-INF/org.eclipse.e4.core.di.internal.extensions.ServiceSupplier.xml
@@ -1,8 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.e4.core.di.internal.extensions.ServiceSupplier">
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.3.0" name="org.eclipse.e4.core.di.internal.extensions.ServiceSupplier">
    <property name="dependency.injection.annotation" type="String" value="org.eclipse.e4.core.di.extensions.Service"/>
+   <property name="event.topics" value="org/eclipse/e4/core/contexts/IEclipseContext/DISPOSE"/>
    <service>
       <provide interface="org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier"/>
+      <provide interface="org.osgi.service.event.EventHandler"/>
    </service>
+   <reference cardinality="0..1" field="logService" interface="org.osgi.service.log.LogService" name="logService" policy="dynamic"/>
    <implementation class="org.eclipse.e4.core.di.internal.extensions.ServiceSupplier"/>
 </scr:component>
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/EventObjectSupplier.java b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/EventObjectSupplier.java
index 4928011..1dfe5e3 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/EventObjectSupplier.java
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/EventObjectSupplier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2016 IBM Corporation and others.
+ * Copyright (c) 2010, 2017 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
@@ -23,6 +23,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import javax.annotation.PreDestroy;
+import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.di.IInjector;
 import org.eclipse.e4.core.di.InjectionException;
 import org.eclipse.e4.core.di.extensions.EventTopic;
@@ -42,9 +43,11 @@
 /**
  * This class is instantiated and wired by declarative services.
  */
-@Component(service = ExtendedObjectSupplier.class, immediate = true, property = "dependency.injection.annotation=org.eclipse.e4.core.di.extensions.EventTopic")
-public class EventObjectSupplier extends ExtendedObjectSupplier {
-	
+@Component(service = { ExtendedObjectSupplier.class, EventHandler.class }, property = {
+		"dependency.injection.annotation=org.eclipse.e4.core.di.extensions.EventTopic",
+		"event.topics=" + IEclipseContext.TOPIC_DISPOSE }, immediate = true)
+public class EventObjectSupplier extends ExtendedObjectSupplier implements EventHandler {
+
 	// Same as IEventBroker.DATA
 	public static final String DATA = "org.eclipse.e4.data"; //$NON-NLS-1$
 
@@ -168,6 +171,7 @@
 		Class<?> descriptorsClass = getDesiredClass(descriptor.getDesiredType());
 		if (descriptorsClass.equals(Event.class))
 			return currentEvents.get(topic);
+
 		return currentEvents.get(topic).getProperty(DATA);
 	}
 
@@ -248,4 +252,20 @@
 		return null;
 	}
 
+	@Override
+	public void handleEvent(Event event) {
+		synchronized (registrations) {
+			Iterator<Entry<Subscriber, ServiceRegistration<EventHandler>>> i = registrations.entrySet().iterator();
+			while (i.hasNext()) {
+				Entry<Subscriber, ServiceRegistration<EventHandler>> entry = i.next();
+				Subscriber key = entry.getKey();
+				if (!key.getRequestor().isValid()) {
+					ServiceRegistration<EventHandler> registration = entry.getValue();
+					registration.unregister();
+					i.remove();
+				}
+			}
+		}
+	}
+
 }
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/OSGiObjectSupplier.java b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/OSGiObjectSupplier.java
index 9fa15a0..b1478ea 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/OSGiObjectSupplier.java
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/OSGiObjectSupplier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2016 Markus Alexander Kuppe and others. All rights reserved.
+ * Copyright (c) 2013, 2017 Markus Alexander Kuppe 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
@@ -12,7 +12,10 @@
 
 import java.lang.reflect.Type;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
+import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.di.InjectionException;
 import org.eclipse.e4.core.di.annotations.Optional;
 import org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier;
@@ -26,9 +29,13 @@
 import org.osgi.framework.SynchronousBundleListener;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
 
-@Component(service = ExtendedObjectSupplier.class, property = "dependency.injection.annotation=org.eclipse.e4.core.di.extensions.OSGiBundle")
-public class OSGiObjectSupplier extends ExtendedObjectSupplier {
+@Component(service = { ExtendedObjectSupplier.class, EventHandler.class }, property = {
+		"dependency.injection.annotation=org.eclipse.e4.core.di.extensions.OSGiBundle",
+		"event.topics=" + IEclipseContext.TOPIC_DISPOSE })
+public class OSGiObjectSupplier extends ExtendedObjectSupplier implements EventHandler {
 
 	/**
 	 * A Map of Requestor to BundleListener. Each Requestor will only ever request its own bundle and thus there is a 1:1 relationship between R and BL.
@@ -107,4 +114,15 @@
 			requestor2listener.put(requestor, listener);
 		}
 	}
+
+	@Override
+	public void handleEvent(Event event) {
+		for (Iterator<Entry<IRequestor, BundleListener>> it = requestor2listener.entrySet().iterator(); it.hasNext();) {
+			Entry<IRequestor, BundleListener> entry = it.next();
+			if (!entry.getKey().isValid()) {
+				localBundleContext.removeBundleListener(entry.getValue());
+				it.remove();
+			}
+		}
+	}
 }
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/PreferencesObjectSupplier.java b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/PreferencesObjectSupplier.java
index 246f1c4..c77264e 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/PreferencesObjectSupplier.java
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/PreferencesObjectSupplier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2016 IBM Corporation and others.
+ * Copyright (c) 2010, 2017 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
@@ -17,6 +17,7 @@
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
@@ -24,6 +25,7 @@
 import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
 import org.eclipse.core.runtime.preferences.IPreferencesService;
 import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.di.IInjector;
 import org.eclipse.e4.core.di.extensions.Preference;
 import org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier;
@@ -33,13 +35,17 @@
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
 
 /**
  * Note: we do not support byte arrays in preferences at this time. This class
  * is instantiated and wired by declarative services.
  */
-@Component(service = ExtendedObjectSupplier.class, immediate = true, property = "dependency.injection.annotation=org.eclipse.e4.core.di.extensions.Preference")
-public class PreferencesObjectSupplier extends ExtendedObjectSupplier {
+@Component(service = { ExtendedObjectSupplier.class, EventHandler.class }, property = {
+		"dependency.injection.annotation=org.eclipse.e4.core.di.extensions.Preference",
+		"event.topics=" + IEclipseContext.TOPIC_DISPOSE }, immediate = true)
+public class PreferencesObjectSupplier extends ExtendedObjectSupplier implements EventHandler {
 
 	private IPreferencesService preferencesService;
 
@@ -218,4 +224,36 @@
 		}
 	}
 
+	@Override
+	public void handleEvent(Event event) {
+		synchronized (listenerCache) {
+			for (Iterator<Map.Entry<String, HashMap<String, List<PrefInjectionListener>>>> nodesIterator = listenerCache
+					.entrySet().iterator(); nodesIterator.hasNext();) {
+				HashMap<String, List<PrefInjectionListener>> map = nodesIterator.next().getValue();
+				for (Iterator<HashMap.Entry<String, List<PrefInjectionListener>>> valuesIterator = map.entrySet()
+						.iterator(); valuesIterator.hasNext();) {
+					List<PrefInjectionListener> listeners = valuesIterator.next().getValue();
+					if (listeners != null) {
+						for (Iterator<PrefInjectionListener> listenerIterator = listeners.iterator(); listenerIterator
+								.hasNext();) {
+							PrefInjectionListener listener = listenerIterator.next();
+							if (!listener.getRequestor().isValid()) {
+								listener.stopListening();
+								listenerIterator.remove();
+							}
+						}
+
+						if (listeners.isEmpty()) {
+							valuesIterator.remove();
+						}
+					}
+				}
+
+				if (map.isEmpty()) {
+					nodesIterator.remove();
+				}
+			}
+		}
+	}
+
 }
diff --git a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/ServiceSupplier.java b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/ServiceSupplier.java
index 22accb0..3bb4f61 100644
--- a/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/ServiceSupplier.java
+++ b/bundles/org.eclipse.e4.core.di.extensions.supplier/src/org/eclipse/e4/core/di/internal/extensions/ServiceSupplier.java
@@ -16,12 +16,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Predicate;
+import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.di.IInjector;
 import org.eclipse.e4.core.di.InjectionException;
 import org.eclipse.e4.core.di.extensions.Service;
@@ -39,13 +40,17 @@
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
 import org.osgi.service.log.LogService;
 
 /**
  * Supplier for {@link Service}
  */
-@Component(service = ExtendedObjectSupplier.class, property = "dependency.injection.annotation:String=org.eclipse.e4.core.di.extensions.Service")
-public class ServiceSupplier extends ExtendedObjectSupplier {
+@Component(service = { ExtendedObjectSupplier.class, EventHandler.class }, property = {
+		"dependency.injection.annotation=org.eclipse.e4.core.di.extensions.Service",
+		"event.topics=" + IEclipseContext.TOPIC_DISPOSE })
+public class ServiceSupplier extends ExtendedObjectSupplier implements EventHandler {
 
 	@Reference(cardinality = ReferenceCardinality.OPTIONAL)
 	volatile LogService logService;
@@ -64,24 +69,9 @@
 
 		@Override
 		public void serviceChanged(ServiceEvent event) {
+			cleanup();
+
 			synchronized (this.supplier) {
-				Predicate<IRequestor> pr = IRequestor::isValid;
-				this.requestors.removeIf(pr.negate());
-
-				if( this.requestors.isEmpty() ) {
-					Map<Class<?>, ServiceHandler> map = this.supplier.handlerList.get(this.bundleContext);
-					if( map != null ) {
-						map.remove(this.serviceType);
-
-						if( map.isEmpty() ) {
-							this.supplier.handlerList.remove(this.bundleContext);
-						}
-					}
-
-					this.bundleContext.removeServiceListener(this);
-					return;
-				}
-
 				String[] data = (String[]) event.getServiceReference().getProperty(Constants.OBJECTCLASS);
 				for (String d : data) {
 					if (this.serviceType.getName().equals(d)) {
@@ -98,9 +88,30 @@
 				}
 			}
 		}
+
+		public void cleanup() {
+			synchronized (this.supplier) {
+				Predicate<IRequestor> pr = IRequestor::isValid;
+				this.requestors.removeIf(pr.negate());
+
+				if (this.requestors.isEmpty()) {
+					Map<Class<?>, ServiceHandler> map = this.supplier.handlerList.get(this.bundleContext);
+					if (map != null) {
+						map.remove(this.serviceType);
+
+						if (map.isEmpty()) {
+							this.supplier.handlerList.remove(this.bundleContext);
+						}
+					}
+
+					this.bundleContext.removeServiceListener(this);
+					return;
+				}
+			}
+		}
 	}
 
-	Map<BundleContext,Map<Class<?>,ServiceHandler>> handlerList = new HashMap<>();
+	Map<BundleContext, Map<Class<?>, ServiceHandler>> handlerList = new ConcurrentHashMap<>();
 
 	@Override
 	public Object get(IObjectDescriptor descriptor, IRequestor requestor, boolean track, boolean group) {
@@ -188,7 +199,7 @@
 	}
 
 	private synchronized void trackService(BundleContext context, Class<?> serviceClass, IRequestor requestor) {
-		Map<Class<?>, ServiceHandler> map = this.handlerList.computeIfAbsent(context, (k) -> new HashMap<>());
+		Map<Class<?>, ServiceHandler> map = this.handlerList.computeIfAbsent(context, (k) -> new ConcurrentHashMap<>());
 		ServiceHandler handler = map.computeIfAbsent(serviceClass, (cl) -> {
 			ServiceHandler h = new ServiceHandler(this,context, serviceClass);
 			context.addServiceListener(h);
@@ -214,4 +225,12 @@
 		}
 	}
 
+	@Override
+	public void handleEvent(Event event) {
+		this.handlerList.forEach((bc, map) -> {
+			map.forEach((cl, sh) -> {
+				sh.cleanup();
+			});
+		});
+	}
 }
diff --git a/bundles/org.eclipse.e4.core.services/OSGI-INF/org.eclipse.e4.core.internal.services.TranslationObjectSupplier.xml b/bundles/org.eclipse.e4.core.services/OSGI-INF/org.eclipse.e4.core.internal.services.TranslationObjectSupplier.xml
index 7d7c3b2..6102756 100644
--- a/bundles/org.eclipse.e4.core.services/OSGI-INF/org.eclipse.e4.core.internal.services.TranslationObjectSupplier.xml
+++ b/bundles/org.eclipse.e4.core.services/OSGI-INF/org.eclipse.e4.core.internal.services.TranslationObjectSupplier.xml
@@ -1,8 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.eclipse.e4.core.internal.services.TranslationObjectSupplier">
    <property name="dependency.injection.annotation" type="String" value="org.eclipse.e4.core.services.nls.Translation"/>
+   <property name="event.topics" value="org/eclipse/e4/core/contexts/IEclipseContext/DISPOSE"/>
    <service>
       <provide interface="org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier"/>
+      <provide interface="org.osgi.service.event.EventHandler"/>
    </service>
    <implementation class="org.eclipse.e4.core.internal.services.TranslationObjectSupplier"/>
 </scr:component>
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/TranslationObjectSupplier.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/TranslationObjectSupplier.java
index 759d751..5c660ee 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/TranslationObjectSupplier.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/TranslationObjectSupplier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2016 BestSolution.at and others.
+ * Copyright (c) 2011, 2017 BestSolution.at 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
@@ -14,15 +14,17 @@
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.ResourceBundle;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
 import javax.inject.Inject;
 import javax.inject.Named;
+import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.core.di.annotations.Optional;
 import org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier;
 import org.eclipse.e4.core.di.suppliers.IObjectDescriptor;
@@ -33,9 +35,13 @@
 import org.eclipse.e4.core.services.translation.TranslationService;
 import org.eclipse.osgi.service.localization.BundleLocalization;
 import org.osgi.service.component.annotations.Component;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
 
-@Component(service = ExtendedObjectSupplier.class, property = "dependency.injection.annotation:String=org.eclipse.e4.core.services.nls.Translation")
-public class TranslationObjectSupplier extends ExtendedObjectSupplier {
+@Component(service = { ExtendedObjectSupplier.class, EventHandler.class }, property = {
+		"dependency.injection.annotation=org.eclipse.e4.core.services.nls.Translation",
+		"event.topics=" + IEclipseContext.TOPIC_DISPOSE })
+public class TranslationObjectSupplier extends ExtendedObjectSupplier implements EventHandler {
 
 	/**
 	 * The current active locale that gets injected for updating the message instances.
@@ -59,11 +65,10 @@
 	 * Map that contains all {@link IRequestor} that requested an instance of a messages class. Used
 	 * to inform all requestor if the instances have changed due to a locale change.
 	 */
-	private Map<Class<?>, Set<IRequestor>> listeners = new HashMap<>();
+	private Map<Class<?>, Set<IRequestor>> listeners = new ConcurrentHashMap<>();
 
 	@Override
-	public Object get(IObjectDescriptor descriptor, IRequestor requestor, boolean track,
-			boolean group) {
+	public Object get(IObjectDescriptor descriptor, IRequestor requestor, boolean track, boolean group) {
 
 		Class<?> descriptorsClass = getDesiredClass(descriptor.getDesiredType());
 
@@ -123,11 +128,9 @@
 	 *            The {@link IRequestor} that requested the instance.
 	 */
 	private void addListener(Class<?> descriptorsClass, IRequestor requestor) {
-		Set<IRequestor> registered = this.listeners.get(descriptorsClass);
-		if (registered == null) {
-			registered = new HashSet<>();
-			this.listeners.put(descriptorsClass, registered);
-		}
+		Set<IRequestor> registered = this.listeners.computeIfAbsent(descriptorsClass, (dc) -> {
+			return ConcurrentHashMap.newKeySet();
+		});
 		registered.add(requestor);
 	}
 
@@ -162,4 +165,19 @@
 		}
 		return null;
 	}
+
+	@Override
+	public void handleEvent(Event event) {
+		for (Iterator<Entry<Class<?>, Set<IRequestor>>> it = this.listeners.entrySet().iterator(); it.hasNext();) {
+			Map.Entry<Class<?>, Set<IRequestor>> entry = it.next();
+			Set<IRequestor> requestors = entry.getValue();
+			if (requestors != null) {
+				Predicate<IRequestor> predicate = IRequestor::isValid;
+				requestors.removeIf(predicate.negate());
+				if (requestors.isEmpty()) {
+					it.remove();
+				}
+			}
+		}
+	}
 }
\ No newline at end of file