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 1c2a9d6c5..70fde2592 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 @@ -23,7 +23,6 @@ package org.glyptodon.guacamole.net.basic.rest; import com.google.inject.AbstractModule; -import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionService; import org.glyptodon.guacamole.net.basic.rest.protocol.ProtocolRetrievalService; /** @@ -38,7 +37,6 @@ public class RESTModule extends AbstractModule { protected void configure() { // Bind generic low-level services - bind(ConnectionService.class); bind(ProtocolRetrievalService.class); } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnection.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnection.java index 5ef022cd4..57bf4a9c8 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnection.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnection.java @@ -22,13 +22,10 @@ package org.glyptodon.guacamole.net.basic.rest.connection; -import java.util.HashMap; -import java.util.List; import java.util.Map; import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.auth.Connection; -import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.net.basic.rest.connectiongroup.APIConnectionGroup; import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; @@ -60,15 +57,10 @@ public class APIConnection { */ private String protocol; - /** - * The history records associated with this connection. - */ - private List history; - /** * Map of all associated parameter values, indexed by parameter name. */ - private Map parameters = new HashMap(); + private Map parameters; /** * Create an empty APIConnection. @@ -76,7 +68,9 @@ public class APIConnection { public APIConnection() {} /** - * Create an APIConnection from a Connection record. + * Create an APIConnection from a Connection record. Parameters for the + * connection will not be included. + * * @param connection The connection to create this APIConnection from. * @throws GuacamoleException If a problem is encountered while * instantiating this new APIConnection. @@ -84,21 +78,18 @@ public class APIConnection { public APIConnection(Connection connection) throws GuacamoleException { + // Set identifying information this.name = connection.getName(); this.identifier = connection.getIdentifier(); - this.parentIdentifier = connection.getParentIdentifier(); - this.history = connection.getHistory(); - // Use the explicit ROOT group ID + // Set proper parent identifier, using root identifier if needed + this.parentIdentifier = connection.getParentIdentifier(); if (this.parentIdentifier == null) this.parentIdentifier = APIConnectionGroup.ROOT_IDENTIFIER; - + + // Set protocol from configuration GuacamoleConfiguration configuration = connection.getConfiguration(); - this.protocol = configuration.getProtocol(); - - for (String key: configuration.getParameterNames()) - this.parameters.put(key, configuration.getParameter(key)); } @@ -151,14 +142,6 @@ public class APIConnection { this.parentIdentifier = parentIdentifier; } - /** - * Returns the history records associated with this connection. - * @return The history records associated with this connection. - */ - public List getHistory() { - return history; - } - /** * Returns the parameter map for this connection. * @return The parameter map for this connection. diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java index aca765c40..e38402ebc 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java @@ -22,6 +22,8 @@ package org.glyptodon.guacamole.net.basic.rest.connection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import org.glyptodon.guacamole.GuacamoleException; @@ -78,15 +80,16 @@ public class APIConnectionWrapper implements Connection { @Override public GuacamoleConfiguration getConfiguration() { - // Create the GuacamoleConfiguration from the parameter map + // Create the GuacamoleConfiguration with current protocol GuacamoleConfiguration configuration = new GuacamoleConfiguration(); - - Map parameters = apiConnection.getParameters(); - - for(Map.Entry entry : parameters.entrySet()) - configuration.setParameter(entry.getKey(), entry.getValue()); - configuration.setProtocol(apiConnection.getProtocol()); + + // Add parameters, if available + Map parameters = apiConnection.getParameters(); + if (parameters != null) { + for (Map.Entry entry : parameters.entrySet()) + configuration.setParameter(entry.getKey(), entry.getValue()); + } return configuration; } @@ -95,12 +98,14 @@ public class APIConnectionWrapper implements Connection { public void setConfiguration(GuacamoleConfiguration config) { // Create a parameter map from the GuacamoleConfiguration - Map parameters = apiConnection.getParameters(); - for(String key : config.getParameterNames()) + Map parameters = new HashMap(); + for (String key : config.getParameterNames()) parameters.put(key, config.getParameter(key)); - // Set the protocol + // Set protocol and parameters apiConnection.setProtocol(config.getProtocol()); + apiConnection.setParameters(parameters); + } @Override @@ -110,7 +115,7 @@ public class APIConnectionWrapper implements Connection { @Override public List getHistory() throws GuacamoleException { - return apiConnection.getHistory(); + return Collections.EMPTY_LIST; } } 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 103b56643..4e18741c2 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 @@ -23,7 +23,9 @@ package org.glyptodon.guacamole.net.basic.rest.connection; import com.google.inject.Inject; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -39,11 +41,13 @@ import org.glyptodon.guacamole.GuacamoleClientException; 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.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.HTTPException; import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; +import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -68,52 +72,6 @@ public class ConnectionRESTService { @Inject private AuthenticationService authenticationService; - /** - * A service for managing the REST endpoint APIConnection objects. - */ - @Inject - private ConnectionService connectionService; - - /** - * Gets a list of connections with the given ConnectionGroup parentID. - * If no parentID is provided, returns the connections 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 connections - * belong to. If null, the root connection group will be used. - * @return The connection list. - * @throws GuacamoleException If a problem is encountered while listing connections. - */ - @GET - @AuthProviderRESTExposure - public List getConnections(@QueryParam("token") String authToken, @QueryParam("parentID") String parentID) - throws GuacamoleException { - - UserContext userContext = authenticationService.getUserContext(authToken); - - // 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 HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID."); - - Directory connectionDirectory = - parentConnectionGroup.getConnectionDirectory(); - - // Return the converted connection directory - return connectionService.convertConnectionList(connectionDirectory); - - } - /** * Gets an individual connection. * @@ -144,7 +102,92 @@ public class ConnectionRESTService { return new APIConnection(connection); } - + + /** + * Retrieves the parameters associated with a single connection. + * + * @param authToken + * The authentication token that is used to authenticate the user + * performing the operation. + * + * @param connectionID + * The ID of the connection. + * + * @return + * A map of parameter name/value pairs. + * + * @throws GuacamoleException + * If an error occurs while retrieving the connection parameters. + */ + @GET + @Path("/{connectionID}/parameters") + @AuthProviderRESTExposure + public Map getConnectionParameters(@QueryParam("token") String authToken, + @PathParam("connectionID") String connectionID) throws GuacamoleException { + + UserContext userContext = authenticationService.getUserContext(authToken); + + // Get the connection directory + ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); + Directory connectionDirectory = + rootGroup.getConnectionDirectory(); + + // Get the connection + Connection connection = connectionDirectory.get(connectionID); + if (connection == null) + throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID."); + + // Retrieve connection configuration + GuacamoleConfiguration config = connection.getConfiguration(); + + // Convert parameters to map + Map parameters = new HashMap(); + for (String key : config.getParameterNames()) + parameters.put(key, config.getParameter(key)); + + return parameters; + + } + + /** + * Retrieves the usage history of a single connection. + * + * @param authToken + * The authentication token that is used to authenticate the user + * performing the operation. + * + * @param connectionID + * The ID of the connection. + * + * @return + * A list of connection records, describing the start and end times of + * various usages of this connection. + * + * @throws GuacamoleException + * If an error occurs while retrieving the connection history. + */ + @GET + @Path("/{connectionID}/history") + @AuthProviderRESTExposure + public List getConnectionHistory(@QueryParam("token") String authToken, + @PathParam("connectionID") String connectionID) throws GuacamoleException { + + UserContext userContext = authenticationService.getUserContext(authToken); + + // Get the connection directory + ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); + Directory connectionDirectory = + rootGroup.getConnectionDirectory(); + + // Get the connection + Connection connection = connectionDirectory.get(connectionID); + if (connection == null) + throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID."); + + return connection.getHistory(); + + } + /** * Deletes an individual connection. * diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionService.java deleted file mode 100644 index 44449818d..000000000 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionService.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.connection; - -import java.util.ArrayList; -import java.util.List; -import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.net.auth.Connection; -import org.glyptodon.guacamole.net.auth.Directory; - -/** - * A service for performing useful manipulations on REST Connections. - * - * @author James Muehlner - */ -public class ConnectionService { - - /** - * Converts a Connection Directory to a list of APIConnection objects for - * exposing with the REST endpoints. - * - * @param connectionDirectory The Connection Directory to convert for REST endpoint use. - * @return A List of APIConnection objects for use with the REST endpoint. - * @throws GuacamoleException If an error occurs while converting the - * connection directory. - */ - public List convertConnectionList(Directory connectionDirectory) - throws GuacamoleException { - - List restConnections = new ArrayList(); - - for (String connectionID : connectionDirectory.getIdentifiers()) - restConnections.add(new APIConnection(connectionDirectory.get(connectionID))); - - return restConnections; - - } - -} diff --git a/guacamole/src/main/webapp/app/rest/services/connectionService.js b/guacamole/src/main/webapp/app/rest/services/connectionService.js index 3c11fb4e4..190f9ef5c 100644 --- a/guacamole/src/main/webapp/app/rest/services/connectionService.js +++ b/guacamole/src/main/webapp/app/rest/services/connectionService.js @@ -48,28 +48,37 @@ angular.module('rest').factory('connectionService', ['$http', 'authenticationSer }; /** - * Makes a request to the REST API to get the list of connections, - * returning a promise that provides an array of - * @link{Connection} objects if successful. + * Makes a request to the REST API to get the usage history of a single + * connection, returning a promise that provides the corresponding + * array of @link{ConnectionHistoryEntry} objects if successful. * - * @param {String} [parentID=ConnectionGroup.ROOT_IDENTIFIER] - * The ID of the connection group whose child connections should be - * returned. If not provided, the root connection group will be used - * by default. - * - * @returns {Promise.} - * A promise which will resolve with an array of @link{Connection} - * objects upon success. + * @param {String} id + * The identifier of the connection. + * + * @returns {Promise.} + * A promise which will resolve with an array of + * @link{ConnectionHistoryEntry} objects upon success. */ - service.getConnections = function getConnections(parentID) { - - var parentIDParam = ""; - if (parentID) - parentIDParam = "&parentID=" + parentID; - - return $http.get("api/connection?token=" + authenticationService.getCurrentToken() + parentIDParam); + service.getConnectionHistory = function getConnectionHistory(id) { + return $http.get("api/connection/" + id + "/history?token=" + authenticationService.getCurrentToken()); }; - + + /** + * Makes a request to the REST API to get the parameters of a single + * connection, returning a promise that provides the corresponding + * map of parameter name/value pairs if successful. + * + * @param {String} id + * The identifier of the connection. + * + * @returns {Promise.>} + * A promise which will resolve with an map of parameter name/value + * pairs upon success. + */ + service.getConnectionParameters = function getConnectionParameters(id) { + return $http.get("api/connection/" + id + "/parameters?token=" + authenticationService.getCurrentToken()); + }; + /** * Makes a request to the REST API to save a connection, returning a * promise that can be used for processing the results of the call. If the @@ -85,18 +94,9 @@ angular.module('rest').factory('connectionService', ['$http', 'authenticationSer */ service.saveConnection = function saveConnection(connection) { - /* - * FIXME: This should not be necessary. Perhaps the need for this is a - * sign that history should be queried separately, and not reside as - * part of the connection object? - */ - // Do not try to save the connection history records - var connectionToSave = angular.copy(connection); - delete connectionToSave.history; - // If connection is new, add it and set the identifier automatically - if (!connectionToSave.identifier) { - return $http.post("api/connection/?token=" + authenticationService.getCurrentToken(), connectionToSave).success( + if (!connection.identifier) { + return $http.post("api/connection/?token=" + authenticationService.getCurrentToken(), connection).success( // Set the identifier on the new connection function setConnectionID(connectionID){ @@ -109,9 +109,9 @@ angular.module('rest').factory('connectionService', ['$http', 'authenticationSer // Otherwise, update the existing connection else { return $http.post( - "api/connection/" + connectionToSave.identifier + + "api/connection/" + connection.identifier + "?token=" + authenticationService.getCurrentToken(), - connectionToSave); + connection); } }; diff --git a/guacamole/src/main/webapp/app/rest/types/Connection.js b/guacamole/src/main/webapp/app/rest/types/Connection.js index a41cba70f..656cf3fab 100644 --- a/guacamole/src/main/webapp/app/rest/types/Connection.js +++ b/guacamole/src/main/webapp/app/rest/types/Connection.js @@ -70,26 +70,15 @@ angular.module('rest').factory('Connection', [function defineConnection() { */ this.protocol = template.protocol; - /** - * All previous and current usages of this connection, along with - * associated users. - * - * @type ConnectionHistoryEntry[] - * @default [] - */ - this.history = template.history || []; - /** * Connection configuration parameters, as dictated by the protocol in * use, arranged as name/value pairs. This information may not be - * available if the current user lacks permission to update - * connection parameters, even if they otherwise have permission to - * read and use the connection. + * available until directly queried. If this information is + * unavailable, this property will be null or undefined. * * @type Object. - * @default {} */ - this.parameters = template.parameters || {}; + this.parameters = template.parameters; };