Modernize ActionsManager in Debugger API
diff --git a/ide/api.debugger/src/org/netbeans/api/debugger/ActionsManager.java b/ide/api.debugger/src/org/netbeans/api/debugger/ActionsManager.java
index 94e58f4..ac16138 100644
--- a/ide/api.debugger/src/org/netbeans/api/debugger/ActionsManager.java
+++ b/ide/api.debugger/src/org/netbeans/api/debugger/ActionsManager.java
@@ -22,14 +22,13 @@
 import java.beans.*;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
-import java.util.Vector;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -38,6 +37,7 @@
 import org.netbeans.spi.debugger.ActionsProviderListener;
 import org.openide.util.Cancellable;
 import org.openide.util.Mutex;
+import org.openide.util.Pair;
 import org.openide.util.RequestProcessor;
 import org.openide.util.Task;
 
@@ -110,13 +110,13 @@
 
     // variables ...............................................................
     
-    private final Vector<ActionsManagerListener>    listener = new Vector<ActionsManagerListener>();
-    private final HashMap<String, List<ActionsManagerListener>> listeners = new HashMap<String, List<ActionsManagerListener>>();
+    private final List<ActionsManagerListener>    listener = new ArrayList<>();
+    private final HashMap<String, List<ActionsManagerListener>> listeners = new HashMap<>();
     private HashMap<Object, List<ActionsProvider>>  actionProviders;
     private final Object            actionProvidersLock = new Object();
     private final AtomicBoolean     actionProvidersInitialized = new AtomicBoolean(false);
-    private MyActionListener        actionListener = new MyActionListener ();
-    private Lookup                  lookup;
+    private final ActionsProviderListener actionListener = (Object action, boolean enabled) -> fireActionStateChanged (action);
+    private final Lookup            lookup;
     private boolean                 doiingDo = false;
     private boolean                 destroy = false;
     private volatile List<? extends ActionsProvider> aps;
@@ -140,21 +140,16 @@
      *
      * @param action action constant (default set of constants are defined
      *    in this class with ACTION_ prefix)
-     * @return true if action has been performed
      */
     public final void doAction (final Object action) {
         doiingDo = true;
         List<ActionsProvider> l = getActionProvidersForActionWithInit(action);
         boolean done = false;
-        if (l != null) {
-            int i, k = l.size ();
-            for (i = 0; i < k; i++) {
-                ActionsProvider ap = l.get(i);
-                if (ap.isEnabled (action)) {
-                    fireActionToBeRun(action);
-                    done = true;
-                    ap.doAction (action);
-                }
+        for (ActionsProvider ap : l) {
+            if (ap.isEnabled (action)) {
+                fireActionToBeRun(action);
+                done = true;
+                ap.doAction (action);
             }
         }
         if (done) {
@@ -195,54 +190,39 @@
         
         List<ActionsProvider> l = getActionProvidersForActionWithInit(action);
         boolean posted = false;
-        int k;
-        if (l != null) {
-            k = l.size ();
-        } else {
-            k = 0;
-        }
         
-        List<ActionsProvider> postedActions = new ArrayList<>(k);
+        List<ActionsProvider> postedActions = new ArrayList<>(l.size());
         final AsynchActionTask task = new AsynchActionTask(postedActions);
-        if (l != null) {
-            int i;
-            for (i = 0; i < k; i++) {
-                ActionsProvider ap = l.get (i);
-                if (ap.isEnabled (action)) {
-                    postedActions.add(ap);
-                    posted = true;
-                }
-            }
-            if (posted) {
-                final int[] count = new int[] { 0 };
-                Runnable notifier = new Runnable() {
-                    @Override
-                    public void run() {
-                        synchronized (count) {
-                            if (--count[0] == 0) {
-                                task.actionDone();
-                                fireActionDone (action);
-                                doiingDo = false;
-                                if (destroy) {
-                                    destroyIn ();
-                                }
-                            }
-                        }
-                    }
-                };
-                if (postedActions.size() > 1) {
-                    // We have more than one action provider for a single action.
-                    // Check their paths and choose the most specific one:
-                    postedActions = selectTheMostSpecific(postedActions);
-                }
-                count[0] = k = postedActions.size();
-                fireActionToBeRun(action);
-                for (i = 0; i < k; i++) {
-                    postedActions.get(i).postAction (action, notifier);
-                }
+        for (ActionsProvider ap : l) {
+            if (ap.isEnabled (action)) {
+                postedActions.add(ap);
+                posted = true;
             }
         }
-        if (!posted) {
+        if (posted) {
+            if (postedActions.size() > 1) {
+                // We have more than one action provider for a single action.
+                // Check their paths and choose the most specific one:
+                postedActions = selectTheMostSpecific(postedActions);
+            }
+            //final int[] count = new int[] { postedActions.size() };
+            final AtomicInteger count = new AtomicInteger(postedActions.size());
+            Runnable notifier = () -> {
+                if (count.decrementAndGet() == 0) {
+                    task.actionDone();
+                    fireActionDone (action);
+                    doiingDo = false;
+                    if (destroy) {
+                        destroyIn ();
+                    }
+                }
+            };
+            fireActionToBeRun(action);
+            for (ActionsProvider pa : postedActions) {
+                pa.postAction (action, notifier);
+
+            }
+        } else {
             doiingDo = false;
             if (destroy) {
                 destroyIn ();
@@ -254,90 +234,53 @@
 
     private Task postActionWithLazyInit(final Object action) {
         final AsynchActionTask task = new AsynchActionTask(Collections.emptyList());
-        new RequestProcessor(ActionsManager.class).post(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    doAction(action);
-                } finally {
-                    task.actionDone();
-                }
+        new RequestProcessor(ActionsManager.class).post(() -> {
+            try {
+                doAction(action);
+            } finally {
+                task.actionDone();
             }
         });
         return task;
     }
     
     private static List<ActionsProvider> selectTheMostSpecific(List<ActionsProvider> aps) {
-        Iterator<ActionsProvider> it = aps.iterator();
-        ActionsProvider ap = it.next();
-        String path = getPath(ap);
-        if (path == null) {
-            return aps;
-        }
-        /*
-        Map<String, ActionsProvider> providersByPath = new LinkedHashMap<String, ActionsProvider>();
-        providersByPath.put(path, ap);
-        while(it.hasNext()) {
-            ap = it.next();
-            path = getPath(ap);
+        // This method is called in the rare case of two debugger plugin are registered for the same language
+        // It tries to detect which implementation is more specific.
+        ArrayList<Pair<String, ActionsProvider>> providersByPath = new ArrayList<>();
+
+        for (ActionsProvider ap : aps) {
+            String path = getPath(ap);
             if (path == null) {
                 return aps;
-            } else {
-                providersByPath.put(path, ap);
             }
+            providersByPath.add(Pair.of(path, ap));
         }
-        for (String p1 : providersByPath.keySet()) {
-            
-        }*/
-        int n = aps.size();
-        String[] paths = new String[n];
-        ActionsProvider[] apArr = new ActionsProvider[n];
-        int i = 0;
-        paths[i] = path;
-        apArr[i] = ap;
-        while(it.hasNext()) {
-            ap = it.next();
-            path = getPath(ap);
-            if (path == null) {
-                return aps;
-            } else {
-                i++;
-                paths[i] = path;
-                apArr[i] = ap;
-            }
-        }
-        
-        for (i = 0; i < n; i++) {
-            String p1 = paths[i];
+
+        int n = providersByPath.size();
+        for (int i = 0; i < n; i++) {
+            String p1 = providersByPath.get(i).first();
             for (int j = 0; j < n; j++) {
                 if (i == j) {
                     continue;
                 }
-                String p2 = paths[j];
-                if (p1.startsWith(p2)) {
-                    // p1 is more specific than p2, abandon p2
-                    String[] newPaths = new String[n-1];
-                    ActionsProvider[] newApArr = new ActionsProvider[n-1];
-                    if (j > 0) {
-                        System.arraycopy(paths, 0, newPaths, 0, j);
-                        System.arraycopy(apArr, 0, newApArr, 0, j);
-                    }
-                    if (j < (n-1)) {
-                        System.arraycopy(paths, j+1, newPaths, j, n-1-j);
-                        System.arraycopy(apArr, j+1, newApArr, j, n-1-j);
-                    }
-                    paths = newPaths;
-                    apArr = newApArr;
+                String p2 = providersByPath.get(j).first();
+                if (!p1.equals(p2) && p1.startsWith(p2)) {
+                    providersByPath.remove(j);
                     i--;
                     n--;
                     break;
                 }
             }
         }
-        if (n < aps.size()) {
-            aps = Arrays.asList(apArr);
+        List<ActionsProvider> ret = aps;
+        if (providersByPath.size() < aps.size()) {
+            ret = new LinkedList<>();
+            for (Pair<String, ActionsProvider> pair : providersByPath) {
+                ret.add(pair.second());
+            }
         }
-        return aps;
+        return ret;
     }
     
     private static String getPath(ActionsProvider ap) {
@@ -373,25 +316,16 @@
             if (Mutex.EVENT.isReadAccess()) { // SwingUtilities.isEventDispatchThread()
                 // Need to initialize lazily when called in AWT
                 // A state change will be fired after actions providers are initialized.
-                new RequestProcessor(ActionsManager.class).post(new Runnable() {
-                    @Override
-                    public void run() {
-                        initActionImpls();
-                    }
-                });
+                new RequestProcessor(ActionsManager.class).post(() -> initActionImpls());
             } else {
                 initActionImpls();
             }
         }
 
         List<ActionsProvider> l = getActionProvidersForAction(action);
-        if (l != null) {
-            int i, k = l.size ();
-            for (i = 0; i < k; i++) {
-                ActionsProvider ap = l.get (i);
-                if (ap.isEnabled (action)) {
-                    return true;
-                }
+        for (ActionsProvider ap : l) {
+            if (ap.isEnabled (action)) {
+                return true;
             }
         }
         return false;
@@ -416,7 +350,9 @@
      * @param l listener instance
      */
     public void addActionsManagerListener (ActionsManagerListener l) {
-        listener.addElement (l);
+        synchronized (listener) {
+            listener.add(l);
+        }
     }
 
     /**
@@ -425,7 +361,9 @@
      * @param l listener instance
      */
     public void removeActionsManagerListener (ActionsManagerListener l) {
-        listener.removeElement (l);
+        synchronized (listener) {
+            listener.remove(l);
+        }
     }
 
     /** 
@@ -478,19 +416,14 @@
         List<ActionsManagerListener> l1;
         synchronized (listeners) {
             l1 = listeners.get("actionToBeRun");
-            if (l1 != null) {
-                l1 = new ArrayList<ActionsManagerListener>(l1);
-            }
+            l1 = l1 != null ? new ArrayList<>(l1) : Collections.emptyList();
         }
-        if (l1 != null) {
-            int k = l1.size ();
-            PropertyChangeEvent e = new PropertyChangeEvent(this, "actionToBeRun", null, action);
-            for (int i = 0; i < k; i++) {
-                ActionsManagerListener aml = l1.get(i);
-                if (aml instanceof PropertyChangeListener) {
-                    ((PropertyChangeListener) aml).propertyChange(e);
-                }
+        PropertyChangeEvent e = new PropertyChangeEvent(this, "actionToBeRun", null, action);
+        for (ActionsManagerListener aml : l1) {
+            if (aml instanceof PropertyChangeListener) {
+                ((PropertyChangeListener) aml).propertyChange(e);
             }
+
         }
     }
 
@@ -512,19 +445,13 @@
         List<ActionsManagerListener> l1;
         synchronized (listeners) {
             l1 = listeners.get(ActionsManagerListener.PROP_ACTION_PERFORMED);
-            if (l1 != null) {
-                l1 = new ArrayList<>(l1);
-            }
+            l1 = l1 != null ? new ArrayList<>(l1) : Collections.emptyList();
         }
-        int i, k = l.size ();
-        for (i = 0; i < k; i++) {
-            l.get(i).actionPerformed(action);
+        for (ActionsManagerListener aml : l) {
+            aml.actionPerformed(action);
         }
-        if (l1 != null) {
-            k = l1.size ();
-            for (i = 0; i < k; i++) {
-                l1.get(i).actionPerformed(action);
-            }
+        for (ActionsManagerListener aml : l1) {
+            aml.actionPerformed(action);
         }
     }
 
@@ -547,19 +474,13 @@
         List<ActionsManagerListener> l1;
         synchronized (listeners) {
             l1 = listeners.get(ActionsManagerListener.PROP_ACTION_STATE_CHANGED);
-            if (l1 != null) {
-                l1 = new ArrayList<>(l1);
-            }
+            l1 = l1 != null ? new ArrayList<>(l1) : Collections.emptyList();
         }
-        int i, k = l.size ();
-        for (i = 0; i < k; i++) {
-            l.get(i).actionStateChanged(action, enabled);
+        for (ActionsManagerListener aml : l) {
+            aml.actionStateChanged(action, enabled);
         }
-        if (l1 != null) {
-            k = l1.size ();
-            for (i = 0; i < k; i++) {
-                l1.get(i).actionStateChanged(action, enabled);
-            }
+        for (ActionsManagerListener aml : l1) {
+            aml.actionStateChanged(action, enabled);
         }
     }
     
@@ -567,14 +488,10 @@
     // private support .........................................................
     
     private List<ActionsProvider> getActionProvidersForAction(Object action) {
-        List<ActionsProvider> l;
         synchronized (actionProvidersLock) {
-            l = actionProviders.get(action);
-            if (l != null) {
-                l = new ArrayList<>(l);
-            }
+            List<ActionsProvider> l = actionProviders.get(action);
+            return l != null ? new ArrayList<>(l) : Collections.emptyList();
         }
-        return l;
     }
     
     private List<ActionsProvider> getActionProvidersForActionWithInit(Object action) {
@@ -625,7 +542,7 @@
                     if (ap != null) {
                         sb.append(ap.toString());
                     } else {
-                        sb.append("NULL element in list " + Integer.toHexString(aps.hashCode())); // NOI18N
+                        sb.append("NULL element in list ").append(Integer.toHexString(aps.hashCode())); // NOI18N
                         isNull = true;
                     }
                 }
@@ -671,7 +588,7 @@
     }
 
     private boolean listerersLoaded = false;
-    private List lazyListeners;
+    private List<? extends LazyActionsManagerListener> lazyListeners;
     
     private synchronized void initListeners () {
         if (listerersLoaded) {
@@ -679,22 +596,19 @@
         }
         listerersLoaded = true;
         lazyListeners = lookup.lookup (null, LazyActionsManagerListener.class);
-        int i, k = lazyListeners.size ();
-        for (i = 0; i < k; i++) {
-            LazyActionsManagerListener l = (LazyActionsManagerListener)
-                lazyListeners.get (i);
+        for (LazyActionsManagerListener l : lazyListeners) {
             if (l == null) {
                 // instance could not be created.
                 continue;
             }
             String[] props = l.getProperties ();
+
             if (props == null) {
                 addActionsManagerListener (l);
-                continue;
-            }
-            int j, jj = props.length;
-            for (j = 0; j < jj; j++) {
-                addActionsManagerListener (props [j], l);
+            } else {
+                for (String prop : props) {
+                    addActionsManagerListener (prop, l);
+                }
             }
         }
     }
@@ -708,10 +622,7 @@
         }
         synchronized (this) {
             if (lazyListeners != null) {
-                int i, k = lazyListeners.size ();
-                for (i = 0; i < k; i++) {
-                    LazyActionsManagerListener l = (LazyActionsManagerListener)
-                        lazyListeners.get (i);
+                for (LazyActionsManagerListener l : lazyListeners) {
                     if (l == null) {
                         // instance could not be created.
                         continue;
@@ -720,10 +631,10 @@
                     if (props == null) {
                         removeActionsManagerListener (l);
                         continue;
-                    }
-                    int j, jj = props.length;
-                    for (j = 0; j < jj; j++) {
-                        removeActionsManagerListener (props [j], l);
+                    } else {
+                        for (String prop : props) {
+                            removeActionsManagerListener (prop, l);
+                        }
                     }
                     l.destroy ();
                 }
@@ -732,8 +643,8 @@
         }
         synchronized (actionProvidersLock) {
             Collection<List<ActionsProvider>> apsc = actionProviders.values();
-            for (List<ActionsProvider> aps : apsc) {
-                for (ActionsProvider ap : aps) {
+            for (List<ActionsProvider> ps : apsc) {
+                for (ActionsProvider ap : ps) {
                     ap.removeActionsProviderListener(actionListener);
                 }
             }
@@ -745,9 +656,9 @@
     
     private static class AsynchActionTask extends Task implements Cancellable {
         
-        private Collection postedActions;
+        private final Collection<? extends ActionsProvider> postedActions;
         
-        public AsynchActionTask(Collection postedActions) {
+        public AsynchActionTask(Collection<? extends ActionsProvider> postedActions) {
             this.postedActions = postedActions;
         }
         
@@ -757,9 +668,8 @@
 
         @Override
         public boolean cancel() {
-            for (Iterator it = postedActions.iterator(); it.hasNext(); ) {
-                Object action = it.next();
-                Cancellable c = getCancellable(action);
+            for (ActionsProvider ap : postedActions) {
+                Cancellable c = getCancellable(ap);
                 if (c != null) {
                     if (!c.cancel()) {
                         return false;
@@ -779,20 +689,14 @@
                 // Hack because of ActionsProvider$ContextAware:
                 Field delegateField = action.getClass().getDeclaredField("delegate");   // NOI18N
                 delegateField.setAccessible(true);
-                action = delegateField.get(action);
-                if (action instanceof Cancellable) {
+                Object delegate = delegateField.get(action);
+                if (delegate instanceof Cancellable) {
                     return (Cancellable) action;
                 }
-            } catch (Exception ex) {}
+            } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException ex) {}
             return null;
         }
     }
     
-    class MyActionListener implements ActionsProviderListener {
-        @Override
-        public void actionStateChange (Object action, boolean enabled) {
-            fireActionStateChanged (action);
-        }
-    }
 }