Bug 331260 - Implement an extensible translation service
diff --git a/bundles/org.eclipse.e4.core.services/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.core.services/META-INF/MANIFEST.MF
index 484f3ca..ceab5d2 100644
--- a/bundles/org.eclipse.e4.core.services/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.e4.core.services/META-INF/MANIFEST.MF
@@ -49,4 +49,4 @@
 Eclipse-ExtensibleAPI: true
 Bundle-ClassPath: injection_annotations.jar, .
 Bundle-Activator: org.eclipse.e4.core.internal.services.ServicesActivator
-Service-Component: OSGI-INF/translationService.xml
+Service-Component: OSGI-INF/translationService.xml, OSGI-INF/messagefactory.xml
diff --git a/bundles/org.eclipse.e4.core.services/OSGI-INF/messagefactory.xml b/bundles/org.eclipse.e4.core.services/OSGI-INF/messagefactory.xml
new file mode 100644
index 0000000..e9dd9fd
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/OSGI-INF/messagefactory.xml
@@ -0,0 +1,7 @@
+<?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.services.messagefactory">
+   <implementation class="org.eclipse.e4.core.internal.services.MessageFactoryServiceImpl"/>
+   <service>
+      <provide interface="org.eclipse.e4.core.services.translation.IMessageFactoryService"/>
+   </service>
+</scr:component>
diff --git a/bundles/org.eclipse.e4.core.services/build.properties b/bundles/org.eclipse.e4.core.services/build.properties
index 64ceec5..3221b82 100644
--- a/bundles/org.eclipse.e4.core.services/build.properties
+++ b/bundles/org.eclipse.e4.core.services/build.properties
@@ -5,6 +5,7 @@
                .options,\
                about.html,\
                plugin.properties,\
-               OSGI-INF/
+               OSGI-INF/,\
+               OSGI-INF/messagefactory.xml
 src.includes = schema/
 source.. = src/
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/MessageFactory.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/MessageFactoryServiceImpl.java
similarity index 77%
rename from bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/MessageFactory.java
rename to bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/MessageFactoryServiceImpl.java
index 8799820..100f9e6 100644
--- a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/MessageFactory.java
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/internal/services/MessageFactoryServiceImpl.java
@@ -8,7 +8,7 @@
  *  Contributors:
  *      Tom Schind<tom.schindl@bestsolution.at> - initial API and implementation
  ******************************************************************************/
-package org.eclipse.e4.core.services.translation;
+package org.eclipse.e4.core.internal.services;
 
 import java.lang.ref.Reference;
 import java.lang.ref.SoftReference;
@@ -18,25 +18,31 @@
 import java.security.PrivilegedAction;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
+import org.eclipse.e4.core.services.translation.IMessageFactoryService;
+import org.eclipse.e4.core.services.translation.ITranslationService;
+import org.eclipse.e4.core.services.translation.Message;
 import org.eclipse.e4.core.services.translation.Message.ReferenceType;
+import org.eclipse.e4.core.services.translation.PropertiesBundleTranslationProvider;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceReference;
 
-public class MessageFactory {
-	// TODO Clean up maps
+public class MessageFactoryServiceImpl implements IMessageFactoryService {
 
 	// Cache so when multiple instance use the same message class
-	private static Map<Object, Reference<Object>> SOFT_CACHE = Collections
+	private Map<Object, Reference<Object>> SOFT_CACHE = Collections
 			.synchronizedMap(new HashMap<Object, Reference<Object>>());
 
-	private static Map<Object, Reference<Object>> WEAK_CACHE = Collections
+	private Map<Object, Reference<Object>> WEAK_CACHE = Collections
 			.synchronizedMap(new HashMap<Object, Reference<Object>>());
 
-	@SuppressWarnings("unchecked")
-	public static <M> M createInstance(final String locale, final Class<M> messages)
+	private int CLEANUPCOUNT = 0;
+
+	public <M> M createInstance(final String locale, final Class<M> messages)
 			throws InstantiationException, IllegalAccessException {
 		String key = messages.getName() + "_" + locale;
 
@@ -44,6 +50,23 @@
 		Map<Object, Reference<Object>> cache = null;
 		ReferenceType type = ReferenceType.NONE;
 
+		if (++CLEANUPCOUNT > 1000) {
+			Iterator<Entry<Object, Reference<Object>>> it = WEAK_CACHE.entrySet().iterator();
+			while (it.hasNext()) {
+				if (it.next().getValue().get() == null) {
+					it.remove();
+				}
+			}
+
+			it = SOFT_CACHE.entrySet().iterator();
+			while (it.hasNext()) {
+				if (it.next().getValue().get() == null) {
+					it.remove();
+				}
+			}
+			CLEANUPCOUNT = 0;
+		}
+
 		if (annotation == null || annotation.referenceType() == ReferenceType.SOFT) {
 			cache = SOFT_CACHE;
 			type = ReferenceType.SOFT;
@@ -53,6 +76,7 @@
 		}
 
 		if (cache != null && cache.containsKey(key)) {
+			@SuppressWarnings("unchecked")
 			Reference<M> ref = (Reference<M>) cache.get(key);
 			M o = ref.get();
 			if (o != null) {
@@ -97,7 +121,7 @@
 			throws InstantiationException, IllegalAccessException {
 
 		if (annotation != null && !annotation.providerId().equals("")) {
-			Bundle b = FrameworkUtil.getBundle(MessageFactory.class);
+			Bundle b = FrameworkUtil.getBundle(MessageFactoryServiceImpl.class);
 			BundleContext ctx = b.getBundleContext();
 			ServiceReference<ITranslationService> reference = ctx
 					.getServiceReference(ITranslationService.class);
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/IMessageFactoryService.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/IMessageFactoryService.java
new file mode 100644
index 0000000..3054e8a
--- /dev/null
+++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/translation/IMessageFactoryService.java
@@ -0,0 +1,6 @@
+package org.eclipse.e4.core.services.translation;
+
+public interface IMessageFactoryService {
+	public <M> M createInstance(final String locale, final Class<M> messages)
+			throws InstantiationException, IllegalAccessException;
+}