From e9cebd181b914cb94386d10d48cd802646ac4f58 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 21 Feb 2015 23:41:22 -0800 Subject: [PATCH] GUAC-1100: Implement recursive BFS tree retrieval. --- .../connectiongroup/ConnectionGroupTree.java | 164 +++++++++++++++++- 1 file changed, 160 insertions(+), 4 deletions(-) diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java index 9851710cf..f20bea7a1 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java @@ -22,10 +22,19 @@ package org.glyptodon.guacamole.net.basic.rest.connectiongroup; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; +import org.glyptodon.guacamole.net.basic.rest.connection.APIConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Provides access to the entire tree of connection groups and their @@ -35,11 +44,155 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; */ public class ConnectionGroupTree { + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(ConnectionGroupTree.class); + /** * The root connection group. */ - private final APIConnectionGroup root; + private final ConnectionGroup root; + + /** + * The root connection group as an APIConnectionGroup. + */ + private final APIConnectionGroup rootAPIGroup; + /** + * All connection groups that have been retrieved, stored by their + * identifiers. + */ + private final Map retrievedGroups = + new HashMap(); + + /** + * Adds each of the provided connections to the current tree as children + * of their respective parents. The parent connection groups must already + * be added. + * + * @param connections + * The connections to add to the tree. + * + * @throws GuacamoleException + * If an error occurs while adding the connection to the tree. + */ + private void addConnections(Collection connections) + throws GuacamoleException { + + // Add each connection to the tree + for (Connection connection : connections) { + + // Retrieve the connection's parent group + APIConnectionGroup parent = retrievedGroups.get(connection.getParentIdentifier()); + if (parent != null) { + + Collection children = parent.getChildConnections(); + + // Create child collection if it does not yet exist + if (children == null) { + children = new ArrayList(); + parent.setChildConnections(children); + } + + // Add child + children.add(new APIConnection(connection)); + + } + + // Warn of internal consistency issues + else + logger.debug("Connection \"{}\" cannot be added to the tree: parent \"{}\" does not actually exist.", + connection.getIdentifier(), + connection.getParentIdentifier()); + + } // end for each connection + + } + + /** + * Adds each of the provided connection groups to the current tree as + * children of their respective parents. The parent connection groups must + * already be added. + * + * @param connectionGroups + * The connection groups to add to the tree. + */ + private void addConnectionGroups(Collection connectionGroups) { + + // Add each connection group to the tree + for (ConnectionGroup connectionGroup : connectionGroups) { + + // Retrieve the connection group's parent group + APIConnectionGroup parent = retrievedGroups.get(connectionGroup.getParentIdentifier()); + if (parent != null) { + + Collection children = parent.getChildConnectionGroups(); + + // Create child collection if it does not yet exist + if (children == null) { + children = new ArrayList(); + parent.setChildConnectionGroups(children); + } + + // Add child + APIConnectionGroup apiConnectionGroup = new APIConnectionGroup(connectionGroup); + retrievedGroups.put(connectionGroup.getIdentifier(), apiConnectionGroup); + children.add(apiConnectionGroup); + + } + + // Warn of internal consistency issues + else + logger.debug("Connection group \"{}\" cannot be added to the tree: parent \"{}\" does not actually exist.", + connectionGroup.getIdentifier(), + connectionGroup.getParentIdentifier()); + + } // end for each connection group + + } + + /** + * Adds all descendants of the given parent groups to their corresponding + * parents already stored under root. + * + * @param parents + * The parents whose descendants should be added to the tree. + * + * @throws GuacamoleException + * If an error occurs while retrieving the descendants. + */ + private void addDescendants(Collection parents) + throws GuacamoleException { + + // If no parents, nothing to do + if (parents.isEmpty()) + return; + + Collection childConnectionIdentifiers = new ArrayList(); + Collection childConnectionGroupIdentifiers = new ArrayList(); + + // Build lists of identifiers for retrieval + for (ConnectionGroup parent : parents) { + childConnectionIdentifiers.addAll(parent.getConnectionDirectory().getIdentifiers()); + childConnectionGroupIdentifiers.addAll(parent.getConnectionGroupDirectory().getIdentifiers()); + } + + // Retrieve child connections + if (!childConnectionIdentifiers.isEmpty()) { + Collection childConnections = root.getConnectionDirectory().getAll(childConnectionIdentifiers); + addConnections(childConnections); + } + + // Retrieve child connection groups + if (!childConnectionGroupIdentifiers.isEmpty()) { + Collection childConnectionGroups = root.getConnectionGroupDirectory().getAll(childConnectionGroupIdentifiers); + addConnectionGroups(childConnectionGroups); + addDescendants(childConnectionGroups); + } + + } + /** * Creates a new connection group tree using the given connection group as * the tree root. @@ -62,9 +215,12 @@ public class ConnectionGroupTree { List permissions) throws GuacamoleException { // Store root of tree - this.root = new APIConnectionGroup(root); + this.root = root; + this.rootAPIGroup = new APIConnectionGroup(root); + retrievedGroups.put(root.getIdentifier(), this.rootAPIGroup); - // STUB + // Add all descendants + addDescendants(Collections.singleton(root)); } @@ -78,7 +234,7 @@ public class ConnectionGroupTree { * tree and all connections. */ public APIConnectionGroup getRootAPIConnectionGroup() { - return root; + return rootAPIGroup; } }