@Override
    public boolean removeListener(ArtifactListener listenerToRemove) {
        synchronized(listenersLock) {
            ArtifactListenerSelector listenerSelectorToRemove = new ArtifactListenerSelector(listenerToRemove);
            List<String> pathsToRemove = new ArrayList<String>(1);
            for ( Map.Entry<String, Collection<ArtifactListenerSelector>> listenersEntry : listeners.entrySet() ) {
                for ( ArtifactListenerSelector listener : listenersEntry.getValue() ) {
                    if ( listener.equals(listenerSelectorToRemove)) {
                        pathsToRemove.add( listenersEntry.getKey() );
                        break;
                    }
                }
            }

            Iterator<String> usePathsToRemove = pathsToRemove.iterator();
            while ( usePathsToRemove.hasNext() ) {
                String pathToRemove = usePathsToRemove.next();
                Collection<ArtifactListenerSelector> listenersForPath = listeners.get(pathToRemove);
                if ( listenersForPath.size() == 1 ) {
                    listeners.remove(pathToRemove); // The last listner for the path.
                } else {
                    listenersForPath.remove(listenerSelectorToRemove);
                    usePathsToRemove.remove();
                }
            }

            if ( !pathsToRemove.isEmpty() ) {
                // TODO: Clearing and rebuilding the covering paths collection
                //       Not optimal, but hard to do better, and not necessary
                //       since removals should be rare and the registrations
                //       are expected to be small.
                //
                // Each path which was removed which is a covering path
                // may uncover paths.  Those need to be found and added
                // to the covering paths collection.
                //
                // But, not all paths which were covered should be added,
                // as some the newly uncovered paths may cover other of
                // the newly uncovered paths.
                //
                // Also, an uncovered path which is discovered may itself
                // be a path to removed which hasn't yet been processed.

                coveringPaths.clear();

                for ( String listenerPath : listeners.keySet() ) {
                    @SuppressWarnings("unused")
                    boolean addedUncoveredPath = addCoveringPath(listenerPath);
                }

                // Don't know if the covering paths collection was perturbed.
                // Assume that it was.
                updateMonitor();
            }

            return ( !pathsToRemove.isEmpty() );
        }
    }
@ Override public boolean removeListener ( ArtifactListener listenerToRemove ) { synchronized ( listenersLock ) { ArtifactListenerSelector listenerSelectorToRemove = new ArtifactListenerSelector ( listenerToRemove ) ; List < String > pathsToRemove = new ArrayList < String > ( 1 ) ; for ( Map . Entry < String , Collection < ArtifactListenerSelector > > listenersEntry : listeners . entrySet ( ) ) { for ( ArtifactListenerSelector listener : listenersEntry . getValue ( ) ) { if ( listener . equals ( listenerSelectorToRemove ) ) { pathsToRemove . add ( listenersEntry . getKey ( ) ) ; break ; } } } Iterator < String > usePathsToRemove = pathsToRemove . iterator ( ) ; while ( usePathsToRemove . hasNext ( ) ) { String pathToRemove = usePathsToRemove . next ( ) ; Collection < ArtifactListenerSelector > listenersForPath = listeners . get ( pathToRemove ) ; if ( listenersForPath . size ( ) == 1 ) { listeners . remove ( pathToRemove ) ; } else { listenersForPath . remove ( listenerSelectorToRemove ) ; usePathsToRemove . remove ( ) ; } } if ( ! pathsToRemove . isEmpty ( ) ) { coveringPaths . clear ( ) ; for ( String listenerPath : listeners . keySet ( ) ) { @ SuppressWarnings ( "unused" ) boolean addedUncoveredPath = addCoveringPath ( listenerPath ) ; } updateMonitor ( ) ; } return ( ! pathsToRemove . isEmpty ( ) ) ; } }
Notification API: Remove all registrations of a listener.
See {@link ArtifactNotifier#removeListener(ArtifactListener)}.

@param listenerToRemove The listener which is to be removed.

@return True or false telling if removal of the listener
caused at least one path which had a registered listener
to no longer have a registered listener.