synchronize access to commands to avoid ConcurrentModificationException (FELIX-2870)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1076415 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProcessorImpl.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProcessorImpl.java
index 3ec9566..b48ec1c 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProcessorImpl.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProcessorImpl.java
@@ -21,6 +21,7 @@
 import java.io.InputStream;
 import java.io.PrintStream;
 import java.lang.reflect.Method;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -67,7 +68,7 @@
             session.close();
         }
     }
-    
+
     public void addConverter(Converter c)
     {
         converters.add(c);
@@ -88,10 +89,9 @@
         listeners.remove(l);
     }
 
-
     public Set<String> getCommands()
     {
-        return commands.keySet();
+        return Collections.unmodifiableSet(commands.keySet());
     }
 
     Function getCommand(String name, final Object path)
@@ -104,10 +104,11 @@
         }
 
         name = name.toLowerCase();
-        Object cmd = commands.get(name);
         String cfunction = name.substring(colon);
         boolean anyScope = (colon == 1 && name.charAt(0) == '*');
 
+        Object cmd = commands.get(name);
+
         if (null == cmd && anyScope)
         {
             String scopePath = (null == path ? "*" : path.toString());
@@ -116,12 +117,15 @@
             {
                 if (scope.equals("*"))
                 {
-                    for (Entry<String, Object> entry : commands.entrySet())
+                    synchronized (commands)
                     {
-                        if (entry.getKey().endsWith(cfunction))
+                        for (Entry<String, Object> entry : commands.entrySet())
                         {
-                            cmd = entry.getValue();
-                            break;
+                            if (entry.getKey().endsWith(cfunction))
+                            {
+                                cmd = entry.getValue();
+                                break;
+                            }
                         }
                     }
                 }
@@ -178,22 +182,31 @@
 
     public void addCommand(String scope, Object target, String function)
     {
-        commands.put((scope + ":" + function).toLowerCase(), target);
+        synchronized (commands)
+        {
+            commands.put((scope + ":" + function).toLowerCase(), target);
+        }
     }
 
     public void removeCommand(String scope, String function)
     {
         String func = (scope + ":" + function).toLowerCase();
-        commands.remove(func);
+        synchronized (commands)
+        {
+            commands.remove(func);
+        }
     }
 
     public void removeCommand(Object target)
     {
-        for (Iterator<Object> i = commands.values().iterator(); i.hasNext();)
+        synchronized (commands)
         {
-            if (i.next() == target)
+            for (Iterator<Object> i = commands.values().iterator(); i.hasNext();)
             {
-                i.remove();
+                if (i.next() == target)
+                {
+                    i.remove();
+                }
             }
         }
     }
@@ -226,7 +239,10 @@
 
     protected void put(String name, Object target)
     {
-        commands.put(name, target);
+        synchronized (commands)
+        {
+            commands.put(name, target);
+        }
     }
 
     public Object convert(Class<?> desiredType, Object in)
@@ -279,7 +295,8 @@
         }
     }
 
-    void afterExecute(CommandSession session, CharSequence commandline, Exception exception)
+    void afterExecute(CommandSession session, CharSequence commandline,
+        Exception exception)
     {
         for (CommandSessionListener l : listeners)
         {