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