diff --git a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionGroupService.java b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionGroupService.java
index f4954cb32..2e96c54ac 100644
--- a/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionGroupService.java
+++ b/extensions/guacamole-auth-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/service/ConnectionGroupService.java
@@ -348,7 +348,7 @@ public class ConnectionGroupService {
}
/**
- * Creates a new connection group having the given name and protocol.
+ * Creates a new connection group having the given name and type.
*
* @param name The name to assign to the new connection group.
* @param userID The ID of the user who created this connection group.
diff --git a/guacamole/nb-configuration.xml b/guacamole/nb-configuration.xml
new file mode 100644
index 000000000..4da1f6c9b
--- /dev/null
+++ b/guacamole/nb-configuration.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ ide
+
+
diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTModule.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTModule.java
index 94deb77e4..d7f31b8d7 100644
--- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTModule.java
+++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTModule.java
@@ -28,6 +28,7 @@ import org.glyptodon.guacamole.net.basic.rest.auth.BasicTokenUserContextMap;
import org.glyptodon.guacamole.net.basic.rest.auth.SecureRandomAuthTokenGenerator;
import org.glyptodon.guacamole.net.basic.rest.auth.TokenUserContextMap;
import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionService;
+import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupService;
import org.glyptodon.guacamole.properties.GuacamoleProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -65,6 +66,7 @@ public class RESTModule extends AbstractModule {
bind(AuthenticationProvider.class).toInstance(authProvider);
bind(TokenUserContextMap.class).toInstance(new BasicTokenUserContextMap());
bind(ConnectionService.class);
+ bind(ConnectionGroupService.class);
bind(AuthenticationService.class);
bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class);
diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java
index d11992563..ccb85adbf 100644
--- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java
+++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java
@@ -24,6 +24,7 @@ import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
import org.glyptodon.guacamole.net.basic.rest.auth.LoginRESTService;
import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService;
+import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService;
/**
* A Guice Module to set up the servlet mappings for the Guacamole REST API.
@@ -37,6 +38,7 @@ public class RESTServletModule extends ServletModule {
// Set up the API endpoints
bind(ConnectionRESTService.class);
+ bind(ConnectionGroupRESTService.class);
bind(LoginRESTService.class);
// Set up the servlet and JSON mappings
diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java
index c1ddc1e1c..acfca2b1a 100644
--- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java
+++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java
@@ -250,7 +250,7 @@ public class ConnectionRESTService {
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
- * @param connectionID The ID of the Connection to delete.
+ * @param connectionID The ID of the Connection to move.
* @param connection The connection to update.
*/
@POST
@@ -289,7 +289,7 @@ public class ConnectionRESTService {
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
- * @param connectionID The ID of the Connection to delete.
+ * @param connectionID The ID of the Connection to move.
* @param parentID The ID of the ConnectionGroup the connections
* belong to. If null, the root connection group will be used.
*/
@@ -312,11 +312,8 @@ public class ConnectionRESTService {
if(parentConnectionGroup == null)
throw new GuacamoleClientException("No ConnectionGroup found with the provided parentID.");
- // Make sure the connection is there before trying to delete
- if(connectionDirectory.get(connectionID) == null)
- throw new GuacamoleClientException("No Connection found with the provided ID.");
-
// Move the connection
+ connectionDirectory.move(connectionID, parentConnectionGroup.getConnectionDirectory());
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroup.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroup.java
new file mode 100644
index 000000000..0dfbc177f
--- /dev/null
+++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroup.java
@@ -0,0 +1,110 @@
+package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
+
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup.Type;
+
+/*
+ * Guacamole - Clientless Remote Desktop
+ * Copyright (C) 2010 Michael Jumper
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * A simple connection group to expose through the REST endpoints.
+ *
+ * @author James Muehlner
+ */
+public class APIConnectionGroup {
+
+ /**
+ * The name of this connection group.
+ */
+ private String name;
+
+ /**
+ * The identifier of this connection group.
+ */
+ private String identifier;
+
+ /**
+ * The type of this connection group.
+ */
+ private Type type;
+
+ /**
+ * Create an empty APIConnectionGroup.
+ */
+ public APIConnectionGroup() {}
+
+ /**
+ * Create a new APIConnectionGroup from the given ConnectionGroup record.
+ *
+ * @param connectionGroup The ConnectionGroup record to initialize this
+ * APIConnectionGroup from.
+ */
+ public APIConnectionGroup(ConnectionGroup connectionGroup) {
+ this.identifier = connectionGroup.getIdentifier();
+ this.name = connectionGroup.getName();
+ this.type = connectionGroup.getType();
+ }
+
+ /**
+ * Returns the name of this connection group.
+ * @return The name of this connection group.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the name of this connection group.
+ * @param name The name of this connection group.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the identifier of this connection group.
+ * @return The identifier of this connection group.
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ /**
+ * Set the identifier of this connection group.
+ * @param identifier The identifier of this connection group.
+ */
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ /**
+ * Returns the type of this connection group.
+ * @return The type of this connection group.
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * Set the type of this connection group.
+ * @param type The Type of this connection group.
+ */
+ public void setType(Type type) {
+ this.type = type;
+ }
+}
diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java
new file mode 100644
index 000000000..c61d3812e
--- /dev/null
+++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java
@@ -0,0 +1,95 @@
+package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
+
+/*
+ * Guacamole - Clientless Remote Desktop
+ * Copyright (C) 2010 Michael Jumper
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.net.GuacamoleSocket;
+import org.glyptodon.guacamole.net.auth.Connection;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.net.auth.Directory;
+import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
+
+/**
+ * A wrapper to make an APIConnection look like a ConnectionGroup.
+ * Useful where a org.glyptodon.guacamole.net.auth.ConnectionGroup is required.
+ *
+ * @author James Muehlner
+ */
+public class APIConnectionGroupWrapper implements ConnectionGroup {
+
+ /**
+ * The wrapped APIConnectionGroup.
+ */
+ private APIConnectionGroup apiConnectionGroup;
+
+ /**
+ * Create a new APIConnectionGroupWrapper to wrap the given
+ * APIConnectionGroup as a ConnectionGroup.
+ * @param apiConnectionGroup the APIConnectionGroup to wrap.
+ */
+ public APIConnectionGroupWrapper(APIConnectionGroup apiConnectionGroup) {
+ this.apiConnectionGroup = apiConnectionGroup;
+ }
+
+ @Override
+ public String getName() {
+ return apiConnectionGroup.getName();
+ }
+
+ @Override
+ public void setName(String name) {
+ apiConnectionGroup.setName(name);
+ }
+
+ @Override
+ public String getIdentifier() {
+ return apiConnectionGroup.getIdentifier();
+ }
+
+ @Override
+ public void setIdentifier(String identifier) {
+ apiConnectionGroup.setIdentifier(identifier);
+ }
+
+ @Override
+ public void setType(Type type) {
+ apiConnectionGroup.setType(type);
+ }
+
+ @Override
+ public Type getType() {
+ return apiConnectionGroup.getType();
+ }
+
+ @Override
+ public Directory getConnectionDirectory() throws GuacamoleException {
+ throw new UnsupportedOperationException("Operation not supported.");
+ }
+
+ @Override
+ public Directory getConnectionGroupDirectory() throws GuacamoleException {
+ throw new UnsupportedOperationException("Operation not supported.");
+ }
+
+ @Override
+ public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
+ throw new UnsupportedOperationException("Operation not supported.");
+ }
+
+}
diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java
new file mode 100644
index 000000000..825fdd290
--- /dev/null
+++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java
@@ -0,0 +1,326 @@
+package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
+
+/*
+ * Guacamole - Clientless Remote Desktop
+ * Copyright (C) 2010 Michael Jumper
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+import com.google.inject.Inject;
+import java.util.ArrayList;
+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 javax.ws.rs.core.Response.Status;
+import org.glyptodon.guacamole.GuacamoleClientException;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.GuacamoleSecurityException;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.net.auth.Directory;
+import org.glyptodon.guacamole.net.auth.UserContext;
+import org.glyptodon.guacamole.net.basic.rest.HTTPException;
+import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A REST Service for handling connection group CRUD operations.
+ *
+ * @author James Muehlner
+ */
+@Path("/api/connectionGroup")
+@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;
+
+ /**
+ * A service for managing the REST endpoint APIConnection objects.
+ */
+ @Inject
+ private ConnectionGroupService connectionGroupService;
+
+ /**
+ * Gets a list of connection groups with the given ConnectionGroup parentID.
+ * If no parentID is provided, returns the connection groups from the root group.
+ *
+ * @param authToken The authentication token that is used to authenticate
+ * the user performing the operation.
+ * @param parentID The ID of the ConnectionGroup the connection groups
+ * belong to. If null, the root connection group will be used.
+ * @return The connection list.
+ */
+ @GET
+ public List getConnectionGroups(@QueryParam("token") String authToken, @QueryParam("parentID") String parentID) {
+ UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
+
+ try {
+ // If the parent connection group is passed in, try to find it.
+ ConnectionGroup parentConnectionGroup;
+ if(parentID == null)
+ parentConnectionGroup = userContext.getRootConnectionGroup();
+ else {
+ ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
+ Directory connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
+ parentConnectionGroup = connectionGroupDirectory.get(parentID);
+ }
+
+ if(parentConnectionGroup == null)
+ throw new GuacamoleClientException("No ConnectionGroup found with the provided parentID.");
+
+ Directory connectionGroupDirectory =
+ parentConnectionGroup.getConnectionGroupDirectory();
+
+ // Get the list of connection group names
+ List connectionGroups = new ArrayList();
+ Iterable identifiers = connectionGroupDirectory.getIdentifiers();
+
+ // Get the connection group for each name
+ for(String identifier : identifiers)
+ connectionGroups.add(connectionGroupDirectory.get(identifier));
+
+ return connectionGroupService.convertConnectionGroupList(connectionGroups);
+ } catch(GuacamoleSecurityException e) {
+ throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
+ } catch(GuacamoleClientException e) {
+ throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
+ } catch(GuacamoleException e) {
+ logger.error("Unexpected GuacamoleException caught while listing connection groups.", e);
+ throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
+ }
+ }
+
+ /**
+ * Gets an individual connection group.
+ *
+ * @param authToken The authentication token that is used to authenticate
+ * the user performing the operation.
+ * @param connectionGroupID The ID of the ConnectionGroup.
+ * @return The connection group.
+ */
+ @GET
+ @Path("/{connectionGroupID}")
+ public APIConnectionGroup getConnectionGroup(@QueryParam("token") String authToken,
+ @PathParam("connectionGroupID") String connectionGroupID) {
+ UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
+
+ try {
+ // Get the connection group directory
+ ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
+ Directory connectionGroupDirectory =
+ rootGroup.getConnectionGroupDirectory();
+
+ // Get the connection group
+ ConnectionGroup connectionGroup = connectionGroupDirectory.get(connectionGroupID);
+
+ if(connectionGroup == null)
+ throw new GuacamoleClientException("No ConnectionGroup found with the provided ID.");
+
+ return new APIConnectionGroup(connectionGroup);
+ } catch(GuacamoleSecurityException e) {
+ throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
+ } catch(GuacamoleClientException e) {
+ throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
+ } catch(GuacamoleException e) {
+ logger.error("Unexpected GuacamoleException caught while getting connection group.", e);
+ throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
+ }
+ }
+
+ /**
+ * Deletes an individual connection group.
+ *
+ * @param authToken The authentication token that is used to authenticate
+ * the user performing the operation.
+ * @param connectionGroupID The ID of the ConnectionGroup to delete.
+ */
+ @DELETE
+ @Path("/{connectionGroupID}")
+ public void deleteConnectionGroup(@QueryParam("token") String authToken, @PathParam("connectionGroupID") String connectionGroupID) {
+ UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
+
+ try {
+ // Get the connection group directory
+ ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
+ Directory connectionGroupDirectory =
+ rootGroup.getConnectionGroupDirectory();
+
+ // Make sure the connection is there before trying to delete
+ if(connectionGroupDirectory.get(connectionGroupID) == null)
+ throw new GuacamoleClientException("No Connection found with the provided ID.");
+
+ // Delete the connection group
+ connectionGroupDirectory.remove(connectionGroupID);
+ } catch(GuacamoleSecurityException e) {
+ throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
+ } catch(GuacamoleClientException e) {
+ throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
+ } catch(GuacamoleException e) {
+ logger.error("Unexpected GuacamoleException caught while deleting connection group.", e);
+ throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
+ }
+ }
+
+ /**
+ * Creates a new connection group and returns the identifier of the new connection group.
+ * If a parentID is provided, the connection group will be created in the
+ * connection group with the parentID. Otherwise, the root connection group
+ * will be used.
+ *
+ * @param authToken The authentication token that is used to authenticate
+ * the user performing the operation.
+ * @param parentID The ID of the ConnectionGroup the connection groups
+ * belong to. If null, the root connection group will be used.
+ * @param connection The connection group to create.
+ * @return The identifier of the new connection group.
+ */
+ @POST
+ public String createConnectionGroup(@QueryParam("token") String authToken,
+ @QueryParam("parentID") String parentID, APIConnectionGroup connectionGroup) {
+ UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
+
+ try {
+ if(connectionGroup == null)
+ throw new GuacamoleClientException("A connection group is required for this request.");
+
+ // If the parent connection group is passed in, try to find it.
+ ConnectionGroup parentConnectionGroup;
+ if(parentID == null)
+ parentConnectionGroup = userContext.getRootConnectionGroup();
+ else {
+ ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
+ Directory connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
+ parentConnectionGroup = connectionGroupDirectory.get(parentID);
+ }
+
+ if(parentConnectionGroup == null)
+ throw new GuacamoleClientException("No ConnectionGroup found with the provided parentID.");
+
+ Directory connectionGroupDirectory =
+ parentConnectionGroup.getConnectionGroupDirectory();
+
+ // Create the connection group
+ connectionGroupDirectory.add(new APIConnectionGroupWrapper(connectionGroup));
+
+ // Return the new connection group identifier
+ return connectionGroup.getIdentifier();
+ } catch(GuacamoleSecurityException e) {
+ throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
+ } catch(GuacamoleClientException e) {
+ throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
+ } catch(GuacamoleException e) {
+ logger.error("Unexpected GuacamoleException caught while creating connection.", e);
+ throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
+ }
+ }
+
+ /**
+ * Updates a connection group.
+ *
+ * @param authToken The authentication token that is used to authenticate
+ * the user performing the operation.
+ * @param connectionID The ID of the ConnectionGroup to update.
+ * @param connection The connection group to update.
+ */
+ @POST
+ @Path("/{connectionGroupID}")
+ public void updateConnectionGroup(@QueryParam("token") String authToken,
+ @PathParam("connectionGroupID") String connectionGroupID, APIConnectionGroup connectionGroup) {
+ UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
+
+ try {
+ if(connectionGroup == null)
+ throw new GuacamoleClientException("A connection is required for this request.");
+
+ // Get the connection directory
+ ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
+ Directory connectionGroupDirectory =
+ rootGroup.getConnectionGroupDirectory();
+
+ // Make sure the connection group is there before trying to update
+ if(connectionGroupDirectory.get(connectionGroupID) == null)
+ throw new GuacamoleClientException("No ConnectionGroup with the provided ID.");
+
+ // Update the connection group
+ connectionGroupDirectory.update(new APIConnectionGroupWrapper(connectionGroup));
+ } catch(GuacamoleSecurityException e) {
+ throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
+ } catch(GuacamoleClientException e) {
+ throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
+ } catch(GuacamoleException e) {
+ logger.error("Unexpected GuacamoleException caught updating connection.", e);
+ throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
+ }
+ }
+
+ /**
+ * Moves an individual connection group to a different connection group.
+ *
+ * @param authToken The authentication token that is used to authenticate
+ * the user performing the operation.
+ * @param connectionID The ID of the ConnectionGroup to move.
+ * @param parentID The ID of the ConnectionGroup the connection groups
+ * belong to. If null, the root connection group will be used.
+ */
+ @PUT
+ @Path("/{connectionGroupID}")
+ public void moveConnectionGroup(@QueryParam("token") String authToken,
+ @PathParam("connectionGroupID") String connectionGroupID, @QueryParam("parentID") String parentID) {
+ UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
+
+ try {
+ // Get the connection group directory
+ ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
+ Directory connectionGroupDirectory =
+ rootGroup.getConnectionGroupDirectory();
+
+ // Find the new parent connection group
+ Directory newConnectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
+ ConnectionGroup parentConnectionGroup = newConnectionGroupDirectory.get(parentID);
+
+ if(newConnectionGroupDirectory == null)
+ throw new GuacamoleClientException("No ConnectionGroup found with the provided parentID.");
+
+ // Move the connection
+ connectionGroupDirectory.move(connectionGroupID, parentConnectionGroup.getConnectionGroupDirectory());
+ } catch(GuacamoleSecurityException e) {
+ throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
+ } catch(GuacamoleClientException e) {
+ throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
+ } catch(GuacamoleException e) {
+ logger.error("Unexpected GuacamoleException caught moving connection.", e);
+ throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
+ }
+ }
+
+}
diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupService.java
new file mode 100644
index 000000000..f16241f6c
--- /dev/null
+++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupService.java
@@ -0,0 +1,50 @@
+package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.glyptodon.guacamole.net.auth.Connection;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+
+/*
+ * Guacamole - Clientless Remote Desktop
+ * Copyright (C) 2010 Michael Jumper
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * A service for performing useful manipulations on REST ConnectionGroups.
+ *
+ * @author James Muehlner
+ */
+public class ConnectionGroupService {
+
+ /**
+ * Converts a list of ConnectionGroup to a list of APIConnectionGroup
+ * objects for exposing with the REST endpoints.
+ *
+ * @param connectionGroups The ConnectionGroup to convert for REST endpoint use.
+ * @return A List of APIConnectionGroup objects for use with the REST endpoint.
+ */
+ public List convertConnectionGroupList(
+ List extends ConnectionGroup> connectionGroups) {
+ List restConnectionGroups = new ArrayList();
+
+ for(ConnectionGroup connectionGroup : connectionGroups) {
+ restConnectionGroups.add(new APIConnectionGroup(connectionGroup));
+ }
+
+ return restConnectionGroups;
+ }
+}
diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/package-info.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/package-info.java
new file mode 100644
index 000000000..9b0a3cf17
--- /dev/null
+++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/package-info.java
@@ -0,0 +1,7 @@
+
+/**
+ * Classes related to the connection group manipulation aspect
+ * of the Guacamole REST API.
+ */
+package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
+
diff --git a/guacamole/src/main/webapp/WEB-INF/web.xml b/guacamole/src/main/webapp/WEB-INF/web.xml
index 452f763a5..950848b6f 100644
--- a/guacamole/src/main/webapp/WEB-INF/web.xml
+++ b/guacamole/src/main/webapp/WEB-INF/web.xml
@@ -256,16 +256,6 @@
org.glyptodon.guacamole.net.basic.rest.RESTServletContextListener
-
- com.sun.jersey.api.json.POJOMappingFeature
- true
-
-
-
- com.sun.jersey.config.property.packages
- org.codehaus.jackson.jaxrs
-
-
mp3
audio/mpeg