You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by jm...@apache.org on 2016/07/13 05:09:45 UTC

[07/24] incubator-guacamole-client git commit: GUACAMOLE-5: Replace ConnectionGroupRESTService with new resource-driven implementation.

GUACAMOLE-5: Replace ConnectionGroupRESTService with new resource-driven implementation.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/commit/71c2b4e4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/71c2b4e4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/71c2b4e4

Branch: refs/heads/master
Commit: 71c2b4e4d4c274f5ef1fe2d3f5ecfcd40639de3a
Parents: 06b7887
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Jul 12 11:41:59 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Tue Jul 12 14:53:24 2016 -0700

----------------------------------------------------------------------
 .../guacamole/rest/RESTServiceModule.java       |   4 +-
 .../ConnectionGroupDirectoryResource.java       | 107 +++++++
 .../connectiongroup/ConnectionGroupModule.java  |  65 +++++
 .../ConnectionGroupObjectTranslator.java        |  58 ++++
 .../ConnectionGroupRESTService.java             | 284 -------------------
 .../ConnectionGroupResource.java                | 120 ++++++++
 .../rest/session/UserContextResource.java       |  31 +-
 7 files changed, 382 insertions(+), 287 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/71c2b4e4/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
index c79cb29..c40224e 100644
--- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
@@ -29,13 +29,13 @@ import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
 import org.aopalliance.intercept.MethodInterceptor;
 import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
 import org.apache.guacamole.rest.auth.TokenRESTService;
-import org.apache.guacamole.rest.connectiongroup.ConnectionGroupRESTService;
 import org.apache.guacamole.rest.activeconnection.ActiveConnectionRESTService;
 import org.apache.guacamole.rest.auth.AuthTokenGenerator;
 import org.apache.guacamole.rest.auth.AuthenticationService;
 import org.apache.guacamole.rest.auth.SecureRandomAuthTokenGenerator;
 import org.apache.guacamole.rest.auth.TokenSessionMap;
 import org.apache.guacamole.rest.connection.ConnectionModule;
+import org.apache.guacamole.rest.connectiongroup.ConnectionGroupModule;
 import org.apache.guacamole.rest.history.HistoryRESTService;
 import org.apache.guacamole.rest.language.LanguageRESTService;
 import org.apache.guacamole.rest.patch.PatchRESTService;
@@ -89,7 +89,6 @@ public class RESTServiceModule extends ServletModule {
 
         // Set up the API endpoints
         bind(ActiveConnectionRESTService.class);
-        bind(ConnectionGroupRESTService.class);
         bind(HistoryRESTService.class);
         bind(LanguageRESTService.class);
         bind(PatchRESTService.class);
@@ -104,6 +103,7 @@ public class RESTServiceModule extends ServletModule {
 
         // Resources below root
         install(new ConnectionModule());
+        install(new ConnectionGroupModule());
 
         // Set up the servlet and JSON mappings
         bind(GuiceContainer.class);

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/71c2b4e4/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupDirectoryResource.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupDirectoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupDirectoryResource.java
new file mode 100644
index 0000000..2c32e21
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupDirectoryResource.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.rest.connectiongroup;
+
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.ConnectionGroup;
+import org.apache.guacamole.net.auth.Directory;
+import org.apache.guacamole.net.auth.UserContext;
+import org.apache.guacamole.rest.directory.DirectoryObjectResource;
+import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory;
+import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
+import org.apache.guacamole.rest.directory.DirectoryResource;
+
+/**
+ * A REST resource which abstracts the operations available on a Directory of
+ * ConnectionGroups.
+ *
+ * @author Michael Jumper
+ */
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class ConnectionGroupDirectoryResource
+        extends DirectoryResource<ConnectionGroup, APIConnectionGroup> {
+
+    /**
+     * The UserContext associated with the Directory which contains the
+     * ConnectionGroup exposed by this resource.
+     */
+    private final UserContext userContext;
+
+    /**
+     * The Directory exposed by this resource.
+     */
+    private final Directory<ConnectionGroup> directory;
+
+    /**
+     * A factory which can be used to create instances of resources representing
+     * ConnectionGroups.
+     */
+    private final DirectoryObjectResourceFactory<ConnectionGroup, APIConnectionGroup> resourceFactory;
+
+    /**
+     * Creates a new ConnectionGroupDirectoryResource which exposes the
+     * operations and subresources available for the given ConnectionGroup
+     * Directory.
+     *
+     * @param userContext
+     *     The UserContext associated with the given Directory.
+     *
+     * @param directory
+     *     The Directory being exposed.
+     *
+     * @param translator
+     *     A DirectoryObjectTranslator implementation which handles
+     *     ConnectionGroups.
+     *
+     * @param resourceFactory
+     *     A factory which can be used to create instances of resources
+     *     representing ConnectionGroups.
+     */
+    @AssistedInject
+    public ConnectionGroupDirectoryResource(@Assisted UserContext userContext,
+            @Assisted Directory<ConnectionGroup> directory,
+            DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> translator,
+            DirectoryObjectResourceFactory<ConnectionGroup, APIConnectionGroup> resourceFactory) {
+        super(userContext, directory, translator, resourceFactory);
+        this.userContext = userContext;
+        this.directory = directory;
+        this.resourceFactory = resourceFactory;
+    }
+
+    @Override
+    public DirectoryObjectResource<ConnectionGroup, APIConnectionGroup>
+        getObjectResource(String identifier) throws GuacamoleException {
+
+        // Use root group if identifier is the standard root identifier
+        if (identifier != null && identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER))
+            return resourceFactory.create(userContext, directory,
+                    userContext.getRootConnectionGroup());
+
+        return super.getObjectResource(identifier);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/71c2b4e4/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupModule.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupModule.java b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupModule.java
new file mode 100644
index 0000000..df69919
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupModule.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.rest.connectiongroup;
+
+import com.google.inject.AbstractModule;
+import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory;
+import org.apache.guacamole.rest.directory.DirectoryObjectResource;
+import org.apache.guacamole.rest.directory.DirectoryResourceFactory;
+import com.google.inject.TypeLiteral;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+import org.apache.guacamole.net.auth.ConnectionGroup;
+import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
+import org.apache.guacamole.rest.directory.DirectoryResource;
+
+/**
+ * Guice Module which configures injections required for handling
+ * ConnectionGroup resources via the REST API.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionGroupModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+
+        // Create the required DirectoryResourceFactory implementation
+        install(new FactoryModuleBuilder()
+                .implement(
+                    new TypeLiteral<DirectoryResource<ConnectionGroup, APIConnectionGroup>>() {},
+                    ConnectionGroupDirectoryResource.class
+                )
+                .build(new TypeLiteral<DirectoryResourceFactory<ConnectionGroup, APIConnectionGroup>>() {}));
+
+        // Create the required DirectoryObjectResourceFactory implementation
+        install(new FactoryModuleBuilder()
+                .implement(
+                    new TypeLiteral<DirectoryObjectResource<ConnectionGroup, APIConnectionGroup>>() {},
+                    ConnectionGroupResource.class
+                )
+                .build(new TypeLiteral<DirectoryObjectResourceFactory<ConnectionGroup, APIConnectionGroup>>() {}));
+
+        // Bind translator for converting between ConnectionGroup and APIConnectionGroup
+        bind(new TypeLiteral<DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup>>() {})
+                .to(ConnectionGroupObjectTranslator.class);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/71c2b4e4/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupObjectTranslator.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupObjectTranslator.java b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupObjectTranslator.java
new file mode 100644
index 0000000..efd5cb9
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupObjectTranslator.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.rest.connectiongroup;
+
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.ConnectionGroup;
+import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
+
+/**
+ * Translator which converts between ConnectionGroup objects and
+ * APIConnectionGroup objects.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionGroupObjectTranslator
+        implements DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> {
+
+    @Override
+    public APIConnectionGroup toExternalObject(ConnectionGroup object)
+            throws GuacamoleException {
+        return new APIConnectionGroup(object);
+    }
+
+    @Override
+    public ConnectionGroup toInternalObject(APIConnectionGroup object) {
+        return new APIConnectionGroupWrapper(object);
+    }
+
+    @Override
+    public void applyExternalChanges(ConnectionGroup existingObject,
+            APIConnectionGroup object) {
+
+        // Update the connection group
+        existingObject.setName(object.getName());
+        existingObject.setParentIdentifier(object.getParentIdentifier());
+        existingObject.setType(object.getType());
+        existingObject.setAttributes(object.getAttributes());
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/71c2b4e4/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupRESTService.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupRESTService.java b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupRESTService.java
deleted file mode 100644
index bd28a19..0000000
--- a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupRESTService.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.rest.connectiongroup;
-
-import com.google.inject.Inject;
-import java.util.List;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.MediaType;
-import org.apache.guacamole.GuacamoleClientException;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.net.auth.ConnectionGroup;
-import org.apache.guacamole.net.auth.Directory;
-import org.apache.guacamole.net.auth.UserContext;
-import org.apache.guacamole.net.auth.permission.ObjectPermission;
-import org.apache.guacamole.GuacamoleSession;
-import org.apache.guacamole.rest.ObjectRetrievalService;
-import org.apache.guacamole.rest.auth.AuthenticationService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A REST Service for handling connection group CRUD operations.
- * 
- * @author James Muehlner
- */
-@Path("/data/{dataSource}/connectionGroups")
-@Produces(MediaType.APPLICATION_JSON)
-@Consumes(MediaType.APPLICATION_JSON)
-public class ConnectionGroupRESTService {
-
-    /**
-     * Logger for this class.
-     */
-    private static final Logger logger = LoggerFactory.getLogger(ConnectionGroupRESTService.class);
-    
-    /**
-     * A service for authenticating users from auth tokens.
-     */
-    @Inject
-    private AuthenticationService authenticationService;
-    
-    /**
-     * Service for convenient retrieval of objects.
-     */
-    @Inject
-    private ObjectRetrievalService retrievalService;
-    
-    /**
-     * Gets an individual connection group.
-     * 
-     * @param authToken
-     *     The authentication token that is used to authenticate the user
-     *     performing the operation.
-     * 
-     * @param authProviderIdentifier
-     *     The unique identifier of the AuthenticationProvider associated with
-     *     the UserContext containing the connection group to be retrieved.
-     *
-     * @param connectionGroupID
-     *     The ID of the connection group to retrieve.
-     * 
-     * @return
-     *     The connection group, without any descendants.
-     *
-     * @throws GuacamoleException
-     *     If a problem is encountered while retrieving the connection group.
-     */
-    @GET
-    @Path("/{connectionGroupID}")
-    public APIConnectionGroup getConnectionGroup(@QueryParam("token") String authToken,
-            @PathParam("dataSource") String authProviderIdentifier,
-            @PathParam("connectionGroupID") String connectionGroupID)
-            throws GuacamoleException {
-
-        GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
-
-        // Retrieve the requested connection group
-        return new APIConnectionGroup(retrievalService.retrieveConnectionGroup(session, authProviderIdentifier, connectionGroupID));
-
-    }
-
-    /**
-     * Gets an individual connection group and all children.
-     * 
-     * @param authToken
-     *     The authentication token that is used to authenticate the user
-     *     performing the operation.
-     *
-     * @param authProviderIdentifier
-     *     The unique identifier of the AuthenticationProvider associated with
-     *     the UserContext containing the connection group to be retrieved.
-     *
-     * @param connectionGroupID
-     *     The ID of the connection group to retrieve.
-     *
-     * @param permissions
-     *     If specified and non-empty, limit the returned list to only those
-     *     connections for which the current user has any of the given
-     *     permissions. Otherwise, all visible connections are returned.
-     *     Connection groups are unaffected by this parameter.
-     * 
-     * @return
-     *     The requested connection group, including all descendants.
-     *
-     * @throws GuacamoleException
-     *     If a problem is encountered while retrieving the connection group or
-     *     its descendants.
-     */
-    @GET
-    @Path("/{connectionGroupID}/tree")
-    public APIConnectionGroup getConnectionGroupTree(@QueryParam("token") String authToken, 
-            @PathParam("dataSource") String authProviderIdentifier,
-            @PathParam("connectionGroupID") String connectionGroupID,
-            @QueryParam("permission") List<ObjectPermission.Type> permissions)
-            throws GuacamoleException {
-
-        GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
-        UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
-
-        // Retrieve the requested tree, filtering by the given permissions
-        ConnectionGroup treeRoot = retrievalService.retrieveConnectionGroup(userContext, connectionGroupID);
-        ConnectionGroupTree tree = new ConnectionGroupTree(userContext, treeRoot, permissions);
-
-        // Return tree as a connection group
-        return tree.getRootAPIConnectionGroup();
-
-    }
-
-    /**
-     * Deletes an individual connection group.
-     * 
-     * @param authToken
-     *     The authentication token that is used to authenticate the user
-     *     performing the operation.
-     *
-     * @param authProviderIdentifier
-     *     The unique identifier of the AuthenticationProvider associated with
-     *     the UserContext containing the connection group to be deleted.
-     *
-     * @param connectionGroupID
-     *     The identifier of the connection group to delete.
-     *
-     * @throws GuacamoleException
-     *     If an error occurs while deleting the connection group.
-     */
-    @DELETE
-    @Path("/{connectionGroupID}")
-    public void deleteConnectionGroup(@QueryParam("token") String authToken, 
-            @PathParam("dataSource") String authProviderIdentifier,
-            @PathParam("connectionGroupID") String connectionGroupID)
-            throws GuacamoleException {
-
-        GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
-        UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
-        
-        // Get the connection group directory
-        Directory<ConnectionGroup> connectionGroupDirectory = userContext.getConnectionGroupDirectory();
-
-        // Delete the connection group
-        connectionGroupDirectory.remove(connectionGroupID);
-
-    }
-    
-    /**
-     * Creates a new connection group and returns the new connection group,
-     * with identifier field populated.
-     * 
-     * @param authToken
-     *     The authentication token that is used to authenticate the user
-     *     performing the operation.
-     *
-     * @param authProviderIdentifier
-     *     The unique identifier of the AuthenticationProvider associated with
-     *     the UserContext in which the connection group is to be created.
-     *
-     * @param connectionGroup
-     *     The connection group to create.
-     * 
-     * @return
-     *     The new connection group.
-     *
-     * @throws GuacamoleException
-     *     If an error occurs while creating the connection group.
-     */
-    @POST
-    public APIConnectionGroup createConnectionGroup(
-            @QueryParam("token") String authToken,
-            @PathParam("dataSource") String authProviderIdentifier,
-            APIConnectionGroup connectionGroup) throws GuacamoleException {
-
-        GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
-        UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
-
-        // Validate that connection group data was provided
-        if (connectionGroup == null)
-            throw new GuacamoleClientException("Connection group JSON must be submitted when creating connections groups.");
-
-        // Add the new connection group
-        Directory<ConnectionGroup> connectionGroupDirectory = userContext.getConnectionGroupDirectory();
-        connectionGroupDirectory.add(new APIConnectionGroupWrapper(connectionGroup));
-
-        // Return the new connection group
-        return connectionGroup;
-
-    }
-    
-    /**
-     * Updates a connection group. If the parent identifier of the
-     * connection group is changed, the connection group will also be moved to
-     * the new parent group.
-     * 
-     * @param authToken
-     *     The authentication token that is used to authenticate the user
-     *     performing the operation.
-     *
-     * @param authProviderIdentifier
-     *     The unique identifier of the AuthenticationProvider associated with
-     *     the UserContext containing the connection group to be updated.
-     *
-     * @param connectionGroupID
-     *     The identifier of the existing connection group to update.
-     *
-     * @param connectionGroup
-     *     The data to update the existing connection group with.
-     *
-     * @throws GuacamoleException
-     *     If an error occurs while updating the connection group.
-     */
-    @PUT
-    @Path("/{connectionGroupID}")
-    public void updateConnectionGroup(@QueryParam("token") String authToken, 
-            @PathParam("dataSource") String authProviderIdentifier,
-            @PathParam("connectionGroupID") String connectionGroupID,
-            APIConnectionGroup connectionGroup)
-            throws GuacamoleException {
-
-        GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
-        UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
-        
-        // Validate that connection group data was provided
-        if (connectionGroup == null)
-            throw new GuacamoleClientException("Connection group JSON must be submitted when updating connection groups.");
-
-        // Get the connection group directory
-        Directory<ConnectionGroup> connectionGroupDirectory = userContext.getConnectionGroupDirectory();
-
-        // Retrieve connection group to update
-        ConnectionGroup existingConnectionGroup = retrievalService.retrieveConnectionGroup(userContext, connectionGroupID);
-        
-        // Update the connection group
-        existingConnectionGroup.setName(connectionGroup.getName());
-        existingConnectionGroup.setParentIdentifier(connectionGroup.getParentIdentifier());
-        existingConnectionGroup.setType(connectionGroup.getType());
-        existingConnectionGroup.setAttributes(connectionGroup.getAttributes());
-        connectionGroupDirectory.update(existingConnectionGroup);
-
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/71c2b4e4/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java
new file mode 100644
index 0000000..c0b80c4
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.rest.connectiongroup;
+
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.ConnectionGroup;
+import org.apache.guacamole.net.auth.Directory;
+import org.apache.guacamole.net.auth.UserContext;
+import org.apache.guacamole.net.auth.permission.ObjectPermission;
+import org.apache.guacamole.rest.directory.DirectoryObjectResource;
+import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
+
+/**
+ * A REST resource which abstracts the operations available on an existing
+ * ConnectionGroup.
+ *
+ * @author Michael Jumper
+ */
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class ConnectionGroupResource
+        extends DirectoryObjectResource<ConnectionGroup, APIConnectionGroup> {
+
+    /**
+     * The UserContext associated with the Directory which contains the
+     * ConnectionGroup exposed by this resource.
+     */
+    private final UserContext userContext;
+
+    /**
+     * The ConnectionGroup object represented by this ConnectionGroupResource.
+     */
+    private final ConnectionGroup connectionGroup;
+
+    /**
+     * Creates a new ConnectionGroupResource which exposes the operations and
+     * subresources available for the given ConnectionGroup.
+     *
+     * @param userContext
+     *     The UserContext associated with the given Directory.
+     *
+     * @param directory
+     *     The Directory which contains the given ConnectionGroup.
+     *
+     * @param connectionGroup
+     *     The ConnectionGroup that this ConnectionGroupResource should
+     *     represent.
+     *
+     * @param translator
+     *     A DirectoryObjectTranslator implementation which handles the type of
+     *     object given.
+     */
+    @AssistedInject
+    public ConnectionGroupResource(@Assisted UserContext userContext,
+            @Assisted Directory<ConnectionGroup> directory,
+            @Assisted ConnectionGroup connectionGroup,
+            DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> translator) {
+        super(directory, connectionGroup, translator);
+        this.userContext = userContext;
+        this.connectionGroup = connectionGroup;
+    }
+
+    /**
+     * Returns the current connection group along with all descendants.
+     *
+     * @param permissions
+     *     If specified and non-empty, limit the returned list to only those
+     *     connections for which the current user has any of the given
+     *     permissions. Otherwise, all visible connections are returned.
+     *     ConnectionGroups are unaffected by this parameter.
+     *
+     * @return
+     *     The current connection group, including all descendants.
+     *
+     * @throws GuacamoleException
+     *     If a problem is encountered while retrieving the connection group or
+     *     its descendants.
+     */
+    @GET
+    @Path("tree")
+    public APIConnectionGroup getConnectionGroupTree(
+            @QueryParam("permission") List<ObjectPermission.Type> permissions)
+            throws GuacamoleException {
+
+        // Retrieve the requested tree, filtering by the given permissions
+        ConnectionGroupTree tree = new ConnectionGroupTree(userContext,
+                connectionGroup, permissions);
+
+        // Return tree as a connection group
+        return tree.getRootAPIConnectionGroup();
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/71c2b4e4/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java
index 7518c71..e5d5cb5 100644
--- a/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/session/UserContextResource.java
@@ -30,8 +30,10 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.net.auth.Connection;
+import org.apache.guacamole.net.auth.ConnectionGroup;
 import org.apache.guacamole.net.auth.UserContext;
 import org.apache.guacamole.rest.connection.APIConnection;
+import org.apache.guacamole.rest.connectiongroup.APIConnectionGroup;
 
 /**
  * A REST resource which exposes the contents of a particular UserContext.
@@ -52,7 +54,16 @@ public class UserContextResource {
      * Connection Directory.
      */
     @Inject
-    private DirectoryResourceFactory<Connection, APIConnection> connectionDirectoryResourceFactory;
+    private DirectoryResourceFactory<Connection, APIConnection>
+            connectionDirectoryResourceFactory;
+
+    /**
+     * Factory for creating DirectoryResources which expose a given
+     * ConnectionGroup Directory.
+     */
+    @Inject
+    private DirectoryResourceFactory<ConnectionGroup, APIConnectionGroup>
+            connectionGroupDirectoryResourceFactory;
 
     /**
      * Creates a new UserContextResource which exposes the data within the
@@ -85,4 +96,22 @@ public class UserContextResource {
                 userContext.getConnectionDirectory());
     }
 
+    /**
+     * Returns a new resource which represents the ConnectionGroup Directory
+     * contained within the UserContext exposed by this UserContextResource.
+     *
+     * @return
+     *     A new resource which represents the ConnectionGroup Directory
+     *     contained within the UserContext exposed by this UserContextResource.
+     *
+     * @throws GuacamoleException
+     *     If an error occurs while retrieving the ConnectionGroup Directory.
+     */
+    @Path("connectionGroups")
+    public DirectoryResource<ConnectionGroup, APIConnectionGroup> getConnectionGroupDirectoryResource()
+            throws GuacamoleException {
+        return connectionGroupDirectoryResourceFactory.create(userContext,
+                userContext.getConnectionGroupDirectory());
+    }
+
 }