mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 21:51:23 +00:00
Merge pull request #99 from glyptodon/balancing-groups
GUAC-1101: Implement balancing groups.
This commit is contained in:
@@ -26,6 +26,7 @@ import com.google.inject.Inject;
|
|||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -367,6 +368,7 @@ public class ConnectionService extends DirectoryObjectService<ModeledConnection,
|
|||||||
|
|
||||||
// Get currently-active connections
|
// Get currently-active connections
|
||||||
List<ConnectionRecord> records = new ArrayList<ConnectionRecord>(socketService.getActiveConnections(connection));
|
List<ConnectionRecord> records = new ArrayList<ConnectionRecord>(socketService.getActiveConnections(connection));
|
||||||
|
Collections.reverse(records);
|
||||||
|
|
||||||
// Add past connections from model objects
|
// Add past connections from model objects
|
||||||
for (ConnectionRecordModel model : models)
|
for (ConnectionRecordModel model : models)
|
||||||
|
@@ -23,13 +23,12 @@
|
|||||||
package org.glyptodon.guacamole.auth.jdbc.socket;
|
package org.glyptodon.guacamole.auth.jdbc.socket;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
||||||
@@ -40,6 +39,8 @@ import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionRecordModel;
|
|||||||
import org.glyptodon.guacamole.auth.jdbc.connection.ParameterModel;
|
import org.glyptodon.guacamole.auth.jdbc.connection.ParameterModel;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
|
import org.glyptodon.guacamole.auth.jdbc.user.UserModel;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
|
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||||
|
import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionMapper;
|
||||||
import org.glyptodon.guacamole.environment.Environment;
|
import org.glyptodon.guacamole.environment.Environment;
|
||||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
||||||
import org.glyptodon.guacamole.net.InetGuacamoleSocket;
|
import org.glyptodon.guacamole.net.InetGuacamoleSocket;
|
||||||
@@ -51,6 +52,7 @@ import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
|||||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||||
import org.glyptodon.guacamole.token.StandardTokens;
|
import org.glyptodon.guacamole.token.StandardTokens;
|
||||||
import org.glyptodon.guacamole.token.TokenFilter;
|
import org.glyptodon.guacamole.token.TokenFilter;
|
||||||
|
import org.mybatis.guice.transactional.Transactional;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,6 +70,18 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS
|
|||||||
@Inject
|
@Inject
|
||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapper for accessing connections.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private ConnectionMapper connectionMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for creating connections.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private Provider<ModeledConnection> connectionProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapper for accessing connection parameters.
|
* Mapper for accessing connection parameters.
|
||||||
*/
|
*/
|
||||||
@@ -81,80 +95,34 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS
|
|||||||
private ConnectionRecordMapper connectionRecordMapper;
|
private ConnectionRecordMapper connectionRecordMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current number of concurrent uses of the connection having a given
|
* All active connections to a connection having a given identifier.
|
||||||
* identifier.
|
|
||||||
*/
|
*/
|
||||||
private final Map<String, LinkedList<ConnectionRecord>> activeConnections =
|
private final ActiveConnectionMultimap activeConnections = new ActiveConnectionMultimap();
|
||||||
new HashMap<String, LinkedList<ConnectionRecord>>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Atomically increments the current usage count for the given connection.
|
* All active connections to a connection group having a given identifier.
|
||||||
*
|
|
||||||
* @param connection
|
|
||||||
* The connection which is being used.
|
|
||||||
*/
|
*/
|
||||||
private void addActiveConnection(Connection connection, ConnectionRecord record) {
|
private final ActiveConnectionMultimap activeConnectionGroups = new ActiveConnectionMultimap();
|
||||||
synchronized (activeConnections) {
|
|
||||||
|
|
||||||
String identifier = connection.getIdentifier();
|
|
||||||
|
|
||||||
// Get set of active connection records, creating if necessary
|
|
||||||
LinkedList<ConnectionRecord> connections = activeConnections.get(identifier);
|
|
||||||
if (connections == null) {
|
|
||||||
connections = new LinkedList<ConnectionRecord>();
|
|
||||||
activeConnections.put(identifier, connections);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add active connection
|
|
||||||
connections.addFirst(record);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Atomically decrements the current usage count for the given connection.
|
* Acquires possibly-exclusive access to any one of the given connections
|
||||||
* If a combination of incrementUsage() and decrementUsage() calls result
|
* on behalf of the given user. If access is denied for any reason, or if
|
||||||
* in the usage counter being reduced to zero, it is guaranteed that one
|
* no connection is available, an exception is thrown.
|
||||||
* of those decrementUsage() calls will remove the value from the map.
|
|
||||||
*
|
|
||||||
* @param connection
|
|
||||||
* The connection which is no longer being used.
|
|
||||||
*/
|
|
||||||
private void removeActiveConnection(Connection connection, ConnectionRecord record) {
|
|
||||||
synchronized (activeConnections) {
|
|
||||||
|
|
||||||
String identifier = connection.getIdentifier();
|
|
||||||
|
|
||||||
// Get set of active connection records
|
|
||||||
LinkedList<ConnectionRecord> connections = activeConnections.get(identifier);
|
|
||||||
assert(connections != null);
|
|
||||||
|
|
||||||
// Remove old record
|
|
||||||
connections.remove(record);
|
|
||||||
|
|
||||||
// If now empty, clean the tracking entry
|
|
||||||
if (connections.isEmpty())
|
|
||||||
activeConnections.remove(identifier);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acquires possibly-exclusive access to the given connection on behalf of
|
|
||||||
* the given user. If access is denied for any reason, an exception is
|
|
||||||
* thrown.
|
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user
|
||||||
* The user acquiring access.
|
* The user acquiring access.
|
||||||
*
|
*
|
||||||
* @param connection
|
* @param connections
|
||||||
* The connection being accessed.
|
* The connections being accessed.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The connection that has been acquired on behalf of the given user.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If access is denied to the given user for any reason.
|
* If access is denied to the given user for any reason.
|
||||||
*/
|
*/
|
||||||
protected abstract void acquire(AuthenticatedUser user,
|
protected abstract ModeledConnection acquire(AuthenticatedUser user,
|
||||||
ModeledConnection connection) throws GuacamoleException;
|
List<ModeledConnection> connections) throws GuacamoleException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases possibly-exclusive access to the given connection on behalf of
|
* Releases possibly-exclusive access to the given connection on behalf of
|
||||||
@@ -170,13 +138,43 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS
|
|||||||
protected abstract void release(AuthenticatedUser user,
|
protected abstract void release(AuthenticatedUser user,
|
||||||
ModeledConnection connection);
|
ModeledConnection connection);
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public GuacamoleSocket getGuacamoleSocket(final AuthenticatedUser user,
|
* Creates a socket for the given user which connects to the given
|
||||||
|
* connection, which MUST already be acquired via acquire(). The given
|
||||||
|
* client information will be passed to guacd when the connection is
|
||||||
|
* established.
|
||||||
|
*
|
||||||
|
* The connection will be automatically released when it closes, or if it
|
||||||
|
* fails to establish entirely.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user for whom the connection is being established.
|
||||||
|
*
|
||||||
|
* @param connection
|
||||||
|
* The connection the user is connecting to.
|
||||||
|
*
|
||||||
|
* @param info
|
||||||
|
* Information describing the Guacamole client connecting to the given
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A new GuacamoleSocket which is configured and connected to the given
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while the connection is being established, or
|
||||||
|
* while connection configuration information is being retrieved.
|
||||||
|
*/
|
||||||
|
private GuacamoleSocket connect(final AuthenticatedUser user,
|
||||||
final ModeledConnection connection, GuacamoleClientInformation info)
|
final ModeledConnection connection, GuacamoleClientInformation info)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Create record for active connection
|
// Create record for active connection
|
||||||
final ActiveConnectionRecord activeConnection = new ActiveConnectionRecord(user);
|
final ActiveConnectionRecord activeConnection = new ActiveConnectionRecord(user);
|
||||||
|
|
||||||
|
// Get relevant identifiers
|
||||||
|
final String identifier = connection.getIdentifier();
|
||||||
|
final String parentIdentifier = connection.getParentIdentifier();
|
||||||
|
|
||||||
// Generate configuration from available data
|
// Generate configuration from available data
|
||||||
GuacamoleConfiguration config = new GuacamoleConfiguration();
|
GuacamoleConfiguration config = new GuacamoleConfiguration();
|
||||||
@@ -186,7 +184,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS
|
|||||||
config.setProtocol(model.getProtocol());
|
config.setProtocol(model.getProtocol());
|
||||||
|
|
||||||
// Set parameters from associated data
|
// Set parameters from associated data
|
||||||
Collection<ParameterModel> parameters = parameterMapper.select(connection.getIdentifier());
|
Collection<ParameterModel> parameters = parameterMapper.select(identifier);
|
||||||
for (ParameterModel parameter : parameters)
|
for (ParameterModel parameter : parameters)
|
||||||
config.setParameter(parameter.getName(), parameter.getValue());
|
config.setParameter(parameter.getName(), parameter.getValue());
|
||||||
|
|
||||||
@@ -200,9 +198,9 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS
|
|||||||
// Return new socket
|
// Return new socket
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Atomically gain access to connection
|
// Record new active connection
|
||||||
acquire(user, connection);
|
activeConnections.put(identifier, activeConnection);
|
||||||
addActiveConnection(connection, activeConnection);
|
activeConnectionGroups.put(parentIdentifier, activeConnection);
|
||||||
|
|
||||||
// Return newly-reserved connection
|
// Return newly-reserved connection
|
||||||
return new ConfiguredGuacamoleSocket(
|
return new ConfiguredGuacamoleSocket(
|
||||||
@@ -220,7 +218,8 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS
|
|||||||
super.close();
|
super.close();
|
||||||
|
|
||||||
// Release connection upon close
|
// Release connection upon close
|
||||||
removeActiveConnection(connection, activeConnection);
|
activeConnections.remove(identifier, activeConnection);
|
||||||
|
activeConnectionGroups.remove(parentIdentifier, activeConnection);
|
||||||
release(user, connection);
|
release(user, connection);
|
||||||
|
|
||||||
UserModel userModel = user.getUser().getModel();
|
UserModel userModel = user.getUser().getModel();
|
||||||
@@ -229,7 +228,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS
|
|||||||
// Copy user information and timestamps into new record
|
// Copy user information and timestamps into new record
|
||||||
recordModel.setUserID(userModel.getObjectID());
|
recordModel.setUserID(userModel.getObjectID());
|
||||||
recordModel.setUsername(userModel.getIdentifier());
|
recordModel.setUsername(userModel.getIdentifier());
|
||||||
recordModel.setConnectionIdentifier(connection.getIdentifier());
|
recordModel.setConnectionIdentifier(identifier);
|
||||||
recordModel.setStartDate(activeConnection.getStartDate());
|
recordModel.setStartDate(activeConnection.getStartDate());
|
||||||
recordModel.setEndDate(new Date());
|
recordModel.setEndDate(new Date());
|
||||||
|
|
||||||
@@ -246,7 +245,8 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS
|
|||||||
catch (GuacamoleException e) {
|
catch (GuacamoleException e) {
|
||||||
|
|
||||||
// Atomically release access to connection
|
// Atomically release access to connection
|
||||||
removeActiveConnection(connection, activeConnection);
|
activeConnections.remove(identifier, activeConnection);
|
||||||
|
activeConnectionGroups.remove(parentIdentifier, activeConnection);
|
||||||
release(user, connection);
|
release(user, connection);
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
@@ -256,33 +256,63 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ConnectionRecord> getActiveConnections(Connection connection) {
|
@Transactional
|
||||||
synchronized (activeConnections) {
|
public GuacamoleSocket getGuacamoleSocket(final AuthenticatedUser user,
|
||||||
|
final ModeledConnection connection, GuacamoleClientInformation info)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
String identifier = connection.getIdentifier();
|
// Acquire and connect to single connection
|
||||||
|
acquire(user, Collections.singletonList(connection));
|
||||||
|
return connect(user, connection, info);
|
||||||
|
|
||||||
// Get set of active connection records
|
|
||||||
LinkedList<ConnectionRecord> connections = activeConnections.get(identifier);
|
|
||||||
if (connections != null)
|
|
||||||
return Collections.unmodifiableList(connections);
|
|
||||||
|
|
||||||
return Collections.EMPTY_LIST;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public Collection<ConnectionRecord> getActiveConnections(Connection connection) {
|
||||||
|
return activeConnections.get(connection.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
public GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user,
|
public GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user,
|
||||||
ModeledConnectionGroup connectionGroup,
|
ModeledConnectionGroup connectionGroup,
|
||||||
GuacamoleClientInformation info) throws GuacamoleException {
|
GuacamoleClientInformation info) throws GuacamoleException {
|
||||||
// STUB
|
|
||||||
throw new UnsupportedOperationException("STUB");
|
// If not a balancing group, cannot connect
|
||||||
|
if (connectionGroup.getType() != ConnectionGroup.Type.BALANCING)
|
||||||
|
throw new GuacamoleSecurityException("Permission denied.");
|
||||||
|
|
||||||
|
// If group has no children, cannot connect
|
||||||
|
Collection<String> identifiers = connectionMapper.selectIdentifiersWithin(connectionGroup.getIdentifier());
|
||||||
|
if (identifiers.isEmpty())
|
||||||
|
throw new GuacamoleSecurityException("Permission denied.");
|
||||||
|
|
||||||
|
// Otherwise, retrieve all children
|
||||||
|
Collection<ConnectionModel> models = connectionMapper.select(identifiers);
|
||||||
|
List<ModeledConnection> connections = new ArrayList<ModeledConnection>(models.size());
|
||||||
|
|
||||||
|
// Convert each retrieved model to a modeled connection
|
||||||
|
for (ConnectionModel model : models) {
|
||||||
|
ModeledConnection connection = connectionProvider.get();
|
||||||
|
connection.init(user, model);
|
||||||
|
connections.add(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire and connect to any child
|
||||||
|
ModeledConnection connection = acquire(user, connections);
|
||||||
|
return connect(user, connection, info);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ConnectionRecord> getActiveConnections(ConnectionGroup connectionGroup) {
|
public Collection<ConnectionRecord> getActiveConnections(ConnectionGroup connectionGroup) {
|
||||||
// STUB
|
|
||||||
return Collections.EMPTY_LIST;
|
// If not a balancing group, assume no connections
|
||||||
|
if (connectionGroup.getType() != ConnectionGroup.Type.BALANCING)
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
|
||||||
|
return activeConnectionGroups.get(connectionGroup.getIdentifier());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.auth.jdbc.socket;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping of object identifiers to lists of connection records. Records are
|
||||||
|
* added or removed individually, and the overall list of current records
|
||||||
|
* associated with a given object can be retrieved at any time. The public
|
||||||
|
* methods of this class are all threadsafe.
|
||||||
|
*
|
||||||
|
* @author Michael Jumper
|
||||||
|
*/
|
||||||
|
public class ActiveConnectionMultimap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All active connections to a connection having a given identifier.
|
||||||
|
*/
|
||||||
|
private final Map<String, Set<ConnectionRecord>> records =
|
||||||
|
new HashMap<String, Set<ConnectionRecord>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the given connection record in the list of active connections
|
||||||
|
* associated with the object having the given identifier.
|
||||||
|
*
|
||||||
|
* @param identifier
|
||||||
|
* The identifier of the object being connected to.
|
||||||
|
*
|
||||||
|
* @param record
|
||||||
|
* The record associated with the active connection.
|
||||||
|
*/
|
||||||
|
public void put(String identifier, ConnectionRecord record) {
|
||||||
|
synchronized (records) {
|
||||||
|
|
||||||
|
// Get set of active connection records, creating if necessary
|
||||||
|
Set<ConnectionRecord> connections = records.get(identifier);
|
||||||
|
if (connections == null) {
|
||||||
|
connections = Collections.newSetFromMap(new LinkedHashMap<ConnectionRecord, Boolean>());
|
||||||
|
records.put(identifier, connections);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add active connection
|
||||||
|
connections.add(record);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given connection record from the list of active connections
|
||||||
|
* associated with the object having the given identifier.
|
||||||
|
*
|
||||||
|
* @param identifier
|
||||||
|
* The identifier of the object being disconnected from.
|
||||||
|
*
|
||||||
|
* @param record
|
||||||
|
* The record associated with the active connection.
|
||||||
|
*/
|
||||||
|
public void remove(String identifier, ConnectionRecord record) {
|
||||||
|
synchronized (records) {
|
||||||
|
|
||||||
|
// Get set of active connection records
|
||||||
|
Set<ConnectionRecord> connections = records.get(identifier);
|
||||||
|
assert(connections != null);
|
||||||
|
|
||||||
|
// Remove old record
|
||||||
|
connections.remove(record);
|
||||||
|
|
||||||
|
// If now empty, clean the tracking entry
|
||||||
|
if (connections.isEmpty())
|
||||||
|
records.remove(identifier);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of active connection records associated with the
|
||||||
|
* object having the given identifier. The collection will be sorted in
|
||||||
|
* insertion order. If there are no such connections, an empty collection is
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* @param identifier
|
||||||
|
* The identifier of the object to check.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An immutable collection of records associated with the object having
|
||||||
|
* the given identifier, or an empty collection if there are no such
|
||||||
|
* records.
|
||||||
|
*/
|
||||||
|
public Collection<ConnectionRecord> get(String identifier) {
|
||||||
|
synchronized (records) {
|
||||||
|
|
||||||
|
// Get set of active connection records
|
||||||
|
Collection<ConnectionRecord> connections = records.get(identifier);
|
||||||
|
if (connections != null)
|
||||||
|
return Collections.unmodifiableCollection(connections);
|
||||||
|
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
package org.glyptodon.guacamole.auth.jdbc.socket;
|
package org.glyptodon.guacamole.auth.jdbc.socket;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Collection;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
||||||
@@ -72,18 +72,19 @@ public interface GuacamoleSocketService {
|
|||||||
throws GuacamoleException;
|
throws GuacamoleException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list containing connection records representing all currently-
|
* Returns a connection containing connection records representing all
|
||||||
* active connections using the given connection. These records will have
|
* currently-active connections using the given connection. These records
|
||||||
* usernames and start dates, but no end date.
|
* will have usernames and start dates, but no end date, and will be
|
||||||
|
* sorted in ascending order by start date.
|
||||||
*
|
*
|
||||||
* @param connection
|
* @param connection
|
||||||
* The connection to check.
|
* The connection to check.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* A list containing connection records representing all currently-
|
* A connection containing connection records representing all
|
||||||
* active connections.
|
* currently-active connections.
|
||||||
*/
|
*/
|
||||||
public List<ConnectionRecord> getActiveConnections(Connection connection);
|
public Collection<ConnectionRecord> getActiveConnections(Connection connection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a socket for the given user which connects to the given
|
* Creates a socket for the given user which connects to the given
|
||||||
@@ -116,17 +117,18 @@ public interface GuacamoleSocketService {
|
|||||||
throws GuacamoleException;
|
throws GuacamoleException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list containing connection records representing all currently-
|
* Returns a collection containing connection records representing all
|
||||||
* active connections using the given connection group. These records will
|
* currently-active connections using the given connection group. These
|
||||||
* have usernames and start dates, but no end date.
|
* records will have usernames and start dates, but no end date, and will
|
||||||
|
* be sorted in ascending order by start date.
|
||||||
*
|
*
|
||||||
* @param connectionGroup
|
* @param connectionGroup
|
||||||
* The connection group to check.
|
* The connection group to check.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* A list containing connection records representing all currently-
|
* A collection containing connection records representing all
|
||||||
* active connections.
|
* currently-active connections.
|
||||||
*/
|
*/
|
||||||
public List<ConnectionRecord> getActiveConnections(ConnectionGroup connectionGroup);
|
public Collection<ConnectionRecord> getActiveConnections(ConnectionGroup connectionGroup);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
package org.glyptodon.guacamole.auth.jdbc.socket;
|
package org.glyptodon.guacamole.auth.jdbc.socket;
|
||||||
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
import java.util.List;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
@@ -39,9 +40,25 @@ public class UnrestrictedGuacamoleSocketService
|
|||||||
extends AbstractGuacamoleSocketService {
|
extends AbstractGuacamoleSocketService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void acquire(AuthenticatedUser user, ModeledConnection connection)
|
protected ModeledConnection acquire(AuthenticatedUser user,
|
||||||
throws GuacamoleException {
|
List<ModeledConnection> connections) throws GuacamoleException {
|
||||||
// Do nothing
|
|
||||||
|
ModeledConnection chosen = null;
|
||||||
|
int lowestUsage = 0;
|
||||||
|
|
||||||
|
// Find connection with lowest usage
|
||||||
|
for (ModeledConnection connection : connections) {
|
||||||
|
|
||||||
|
int usage = getActiveConnections(connection).size();
|
||||||
|
if (chosen == null || usage < lowestUsage) {
|
||||||
|
chosen = connection;
|
||||||
|
lowestUsage = usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return chosen;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -110,7 +110,7 @@
|
|||||||
password_salt
|
password_salt
|
||||||
FROM guacamole_user
|
FROM guacamole_user
|
||||||
WHERE
|
WHERE
|
||||||
username = #{identifier,jdbcType=VARCHAR}
|
username = #{username,jdbcType=VARCHAR}
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user