GUAC-932: Migrate to generic service for object retrieval. Add parent update (move) to group service.

This commit is contained in:
Michael Jumper
2014-12-24 23:36:09 -08:00
parent 5e5c36f567
commit f1d20c3c54
5 changed files with 201 additions and 135 deletions

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.glyptodon.guacamole.net.basic.rest;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
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.net.auth.User;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.rest.connectiongroup.APIConnectionGroup;
/**
* Provides easy access and automatic error handling for retrieval of objects,
* such as users, connections, or connection groups. REST API semantics, such
* as the special root connection group identifier, are also handled
* automatically.
*/
public class ObjectRetrievalService {
/**
* Retrieves a single user from the given user context.
*
* @param userContext
* The user context to retrieve the user from.
*
* @param identifier
* The identifier of the user to retrieve.
*
* @return
* The user having the given identifier.
*
* @throws GuacamoleException
* If an error occurs while retrieving the user, or if the
* user does not exist.
*/
public User retrieveUser(UserContext userContext,
String identifier) throws GuacamoleException {
// Get user directory
Directory<String, User> directory = userContext.getUserDirectory();
// Pull specified user
User user = directory.get(identifier);
if (user == null)
throw new GuacamoleResourceNotFoundException("No such user: \"" + identifier + "\"");
return user;
}
/**
* Retrieves a single connection from the given user context.
*
* @param userContext
* The user context to retrieve the connection from.
*
* @param identifier
* The identifier of the connection to retrieve.
*
* @return
* The connection having the given identifier.
*
* @throws GuacamoleException
* If an error occurs while retrieving the connection, or if the
* connection does not exist.
*/
public Connection retrieveConnection(UserContext userContext,
String identifier) throws GuacamoleException {
// Get root directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, Connection> directory = rootGroup.getConnectionDirectory();
// Pull specified connection
Connection connection = directory.get(identifier);
if (connection == null)
throw new GuacamoleResourceNotFoundException("No such connection: \"" + identifier + "\"");
return connection;
}
/**
* Retrieves a single connection group from the given user context. If
* the given identifier the REST API root identifier, the root connection
* group will be returned. The underlying authentication provider may
* additionally use a different identifier for root.
*
* @param userContext
* The user context to retrieve the connection group from.
*
* @param identifier
* The identifier of the connection group to retrieve.
*
* @return
* The connection group having the given identifier, or the root
* connection group if the identifier the root identifier.
*
* @throws GuacamoleException
* If an error occurs while retrieving the connection group, or if the
* connection group does not exist.
*/
public ConnectionGroup retrieveConnectionGroup(UserContext userContext,
String identifier) throws GuacamoleException {
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
// Use root group if identifier is null (or the standard root identifier)
if (identifier != null && identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER))
return rootGroup;
// Pull specified connection group otherwise
Directory<String, ConnectionGroup> directory = rootGroup.getConnectionGroupDirectory();
ConnectionGroup connectionGroup = directory.get(identifier);
if (connectionGroup == null)
throw new GuacamoleResourceNotFoundException("No such connection group: \"" + identifier + "\"");
return connectionGroup;
}
}

View File

@@ -38,6 +38,7 @@ public class RESTModule extends AbstractModule {
// Bind generic low-level services
bind(ProtocolRetrievalService.class);
bind(ObjectRetrievalService.class);
}

View File

@@ -44,8 +44,8 @@ import org.glyptodon.guacamole.net.auth.ConnectionRecord;
import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
import org.glyptodon.guacamole.net.basic.rest.connectiongroup.APIConnectionGroup;
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -71,6 +71,12 @@ public class ConnectionRESTService {
@Inject
private AuthenticationService authenticationService;
/**
* Service for convenient retrieval of objects.
*/
@Inject
private ObjectRetrievalService retrievalService;
/**
* Retrieves an individual connection.
*
@@ -95,17 +101,8 @@ public class ConnectionRESTService {
UserContext userContext = authenticationService.getUserContext(authToken);
// Get the connection directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, Connection> connectionDirectory =
rootGroup.getConnectionDirectory();
// Get the connection
Connection connection = connectionDirectory.get(connectionID);
if (connection == null)
throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\"");
return new APIConnection(connection);
// Retrieve the requested connection
return new APIConnection(retrievalService.retrieveConnection(userContext, connectionID));
}
@@ -138,10 +135,8 @@ public class ConnectionRESTService {
Directory<String, Connection> connectionDirectory =
rootGroup.getConnectionDirectory();
// Get the connection
Connection connection = connectionDirectory.get(connectionID);
if (connection == null)
throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\"");
// Retrieve the requested connection
Connection connection = retrievalService.retrieveConnection(userContext, connectionID);
// Retrieve connection configuration
GuacamoleConfiguration config = connection.getConfiguration();
@@ -181,11 +176,8 @@ public class ConnectionRESTService {
Directory<String, Connection> connectionDirectory =
rootGroup.getConnectionDirectory();
// Get the connection
Connection connection = connectionDirectory.get(connectionID);
if (connection == null)
throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\"");
// Retrieve the requested connection's history
Connection connection = retrievalService.retrieveConnection(userContext, connectionID);
return connection.getHistory();
}
@@ -216,54 +208,11 @@ public class ConnectionRESTService {
Directory<String, Connection> connectionDirectory =
rootGroup.getConnectionDirectory();
// Make sure the connection is there before trying to delete
if (connectionDirectory.get(connectionID) == null)
throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\"");
// Delete the connection
// Delete the specified connection
connectionDirectory.remove(connectionID);
}
/**
* Retrieves a single connection group from the given user context. If
* the given identifier is null or the root identifier, the root connection
* group will be returned.
*
* @param userContext
* The user context to retrieve the connection group from.
*
* @param identifier
* The identifier of the connection group to retrieve.
*
* @return
* The connection group having the given identifier, or the root
* connection group if the identifier is null or the root identifier.
*
* @throws GuacamoleException
* If an error occurs while retrieving the connection group, or if the
* connection group does not exist.
*/
private ConnectionGroup retrieveConnectionGroup(UserContext userContext,
String identifier) throws GuacamoleException {
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
// Use root group if identifier is null (or the standard root identifier)
if (identifier != null && identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER))
return rootGroup;
// Pull specified connection group otherwise
Directory<String, ConnectionGroup> directory = rootGroup.getConnectionGroupDirectory();
ConnectionGroup connectionGroup = directory.get(identifier);
if (connectionGroup == null)
throw new GuacamoleResourceNotFoundException("No such connection group: \"" + identifier + "\"");
return connectionGroup;
}
/**
* Creates a new connection and returns the identifier of the new
* connection.
@@ -294,7 +243,7 @@ public class ConnectionRESTService {
// Retrieve parent group
String parentID = connection.getParentIdentifier();
ConnectionGroup parentConnectionGroup = retrieveConnectionGroup(userContext, parentID);
ConnectionGroup parentConnectionGroup = retrievalService.retrieveConnectionGroup(userContext, parentID);
// Add the new connection
Directory<String, Connection> connectionDirectory = parentConnectionGroup.getConnectionDirectory();
@@ -341,10 +290,8 @@ public class ConnectionRESTService {
rootGroup.getConnectionDirectory();
// Retrieve connection to update
Connection existingConnection = connectionDirectory.get(connectionID);
if (existingConnection == null)
throw new GuacamoleResourceNotFoundException("No such connection: \"" + connectionID + "\"");
Connection existingConnection = retrievalService.retrieveConnection(userContext, connectionID);
// Build updated configuration
GuacamoleConfiguration config = new GuacamoleConfiguration();
config.setProtocol(connection.getProtocol());
@@ -356,7 +303,7 @@ public class ConnectionRESTService {
connectionDirectory.update(existingConnection);
// Update connection parent
ConnectionGroup updatedParentGroup = retrieveConnectionGroup(userContext, connection.getParentIdentifier());
ConnectionGroup updatedParentGroup = retrievalService.retrieveConnectionGroup(userContext, connection.getParentIdentifier());
connectionDirectory.move(connectionID, updatedParentGroup.getConnectionDirectory());
}

View File

@@ -46,6 +46,7 @@ import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
import org.glyptodon.guacamole.net.basic.rest.connection.APIConnection;
import org.slf4j.Logger;
@@ -72,6 +73,12 @@ public class ConnectionGroupRESTService {
@Inject
private AuthenticationService authenticationService;
/**
* Service for convenient retrieval of objects.
*/
@Inject
private ObjectRetrievalService retrievalService;
/**
* Retrieves the given connection group from the user context, including
* all descendant connections and groups if requested.
@@ -105,24 +112,14 @@ public class ConnectionGroupRESTService {
User self = userContext.self();
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
// Retrieve specified connection group
ConnectionGroup connectionGroup;
// Use root group if requested
if (identifier == null || identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER))
connectionGroup = rootGroup;
// Otherwise, query requested group using root group directory
else {
Directory<String, ConnectionGroup> connectionGroupDirectory =
rootGroup.getConnectionGroupDirectory();
// Get the connection group from root directory
connectionGroup = connectionGroupDirectory.get(identifier);
if (connectionGroup == null)
return null;
try {
connectionGroup = retrievalService.retrieveConnectionGroup(userContext, identifier);
}
catch (GuacamoleResourceNotFoundException e) {
return null;
}
// Wrap queried connection group
@@ -274,18 +271,9 @@ public class ConnectionGroupRESTService {
// Get the connection group directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
// Use the root group if it was asked for
if (connectionGroupID != null && connectionGroupID.equals(APIConnectionGroup.ROOT_IDENTIFIER))
connectionGroupID = rootGroup.getIdentifier();
Directory<String, ConnectionGroup> connectionGroupDirectory =
rootGroup.getConnectionGroupDirectory();
// Make sure the connection is there before trying to delete
if (connectionGroupDirectory.get(connectionGroupID) == null)
throw new GuacamoleResourceNotFoundException("No such connection group: \"" + connectionGroupID + "\"");
// Delete the connection group
connectionGroupDirectory.remove(connectionGroupID);
@@ -321,22 +309,9 @@ public class ConnectionGroupRESTService {
if (connectionGroup == null)
throw new GuacamoleClientException("Connection group JSON must be submitted when creating connections groups.");
// Retrieve parent group
String parentID = connectionGroup.getParentIdentifier();
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
// Use root group if no parent is specified
ConnectionGroup parentConnectionGroup;
if (parentID == null)
parentConnectionGroup = rootGroup;
// Pull specified connection group otherwise
else {
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
parentConnectionGroup = connectionGroupDirectory.get(parentID);
if (parentConnectionGroup == null)
throw new GuacamoleResourceNotFoundException("No such connection group: \"" + parentID + "\"");
}
ConnectionGroup parentConnectionGroup = retrievalService.retrieveConnectionGroup(userContext, parentID);
// Add the new connection group
Directory<String, ConnectionGroup> connectionGroupDirectory = parentConnectionGroup.getConnectionGroupDirectory();
@@ -378,22 +353,22 @@ public class ConnectionGroupRESTService {
if (connectionGroup == null)
throw new GuacamoleClientException("Connection group JSON must be submitted when updating connection groups.");
// Get the connection directory
// Get the connection group directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
// Use the root group if it was asked for
if (connectionGroupID != null && connectionGroupID.equals(APIConnectionGroup.ROOT_IDENTIFIER))
connectionGroupID = rootGroup.getIdentifier();
Directory<String, ConnectionGroup> connectionGroupDirectory =
rootGroup.getConnectionGroupDirectory();
// Make sure the connection group is there before trying to update
if (connectionGroupDirectory.get(connectionGroupID) == null)
throw new GuacamoleResourceNotFoundException("No such connection group: \"" + connectionGroupID + "\"");
// Retrieve connection group to update
ConnectionGroup existingConnectionGroup = connectionGroupDirectory.get(connectionGroupID);
// Update the connection group
connectionGroupDirectory.update(new APIConnectionGroupWrapper(connectionGroup));
existingConnectionGroup.setName(connectionGroup.getName());
existingConnectionGroup.setType(connectionGroup.getType());
connectionGroupDirectory.update(existingConnectionGroup);
// Update connection group parent
ConnectionGroup updatedParentGroup = retrievalService.retrieveConnectionGroup(userContext, connectionGroup.getParentIdentifier());
connectionGroupDirectory.move(connectionGroupID, updatedParentGroup.getConnectionGroupDirectory());
}

View File

@@ -54,6 +54,7 @@ import static org.glyptodon.guacamole.net.basic.rest.APIPatch.Operation.add;
import static org.glyptodon.guacamole.net.basic.rest.APIPatch.Operation.remove;
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
import org.glyptodon.guacamole.net.basic.rest.PATCH;
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
import org.glyptodon.guacamole.net.basic.rest.permission.APIPermissionSet;
@@ -105,6 +106,12 @@ public class UserRESTService {
@Inject
private AuthenticationService authenticationService;
/**
* Service for convenient retrieval of objects.
*/
@Inject
private ObjectRetrievalService retrievalService;
/**
* Gets a list of users in the system, filtering the returned list by the
* given permission, if specified.
@@ -177,15 +184,8 @@ public class UserRESTService {
UserContext userContext = authenticationService.getUserContext(authToken);
// Get the directory
Directory<String, User> userDirectory = userContext.getUserDirectory();
// Get the user
User user = userDirectory.get(username);
if (user == null)
throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\"");
// Return the user
// Retrieve the requested user
User user = retrievalService.retrieveUser(userContext, username);
return new APIUser(user);
}
@@ -254,9 +254,7 @@ public class UserRESTService {
"Username in path does not match username provided JSON data.");
// Get the user
User existingUser = userDirectory.get(username);
if (existingUser == null)
throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\"");
User existingUser = retrievalService.retrieveUser(userContext, username);
// Do not update the user password if no password was provided
if (user.getPassword() != null)