private void populateTree( final Node parent, Map<String, Set<Path>> byParent )
        {
            final String parentName = parent.path == null ? null : PluginMetadataHelper.getCanonicalName( parent.path );
            final Set<Path> children = byParent.remove( parentName );
            if ( children != null )
            {
                for ( final Path child : children )
                {
                    final Node node = new Node();
                    node.path = child;
                    if ( !parent.children.add( node ) )
                    {
                        Log.warn( "Detected plugin duplicates for name: '{}'. Only one plugin will be loaded.", node.getName() );
                    }

                    // recurse to find further children.
                    populateTree( node, byParent );
                }
            }
        }
Returns all plugin directories, in a deque of lists with these characteristics:
<ol>
<li>Every list is a hierarchy of parent/child plugins (or is a list of one element).</li>
<li>Every list is ordered to ensure that all parent plugins have a lower index than their children.</li>
<li>The first element of every list will be a plugin that has no 'parent' plugin.</li>
<li>the first element of the first list will be the 'admin' plugin.</li>
</ol>

Plugins within the provided argument that refer to non-existing parent plugins will not be part of the returned
collection.

@param dirs Collections of paths that refer every plugin directory (but not the corresponding .jar/.war files).
@return An ordered collection of paths.
xmppserver/src/main/java/org/jivesoftware/openfire/container/PluginMonitor.java