mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	GUAC-1101: Track connection group usage.
This commit is contained in:
		| @@ -28,10 +28,7 @@ import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.Date; | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; | ||||
| import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; | ||||
| import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; | ||||
| @@ -98,63 +95,14 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | ||||
|     private ConnectionRecordMapper connectionRecordMapper; | ||||
|  | ||||
|     /** | ||||
|      * The current number of concurrent uses of the connection having a given | ||||
|      * identifier. | ||||
|      * All active connections to a connection having a given identifier. | ||||
|      */ | ||||
|     private final Map<String, LinkedList<ConnectionRecord>> activeConnections = | ||||
|             new HashMap<String, LinkedList<ConnectionRecord>>(); | ||||
|     private final ActiveConnectionMultimap activeConnections = new ActiveConnectionMultimap(); | ||||
|  | ||||
|     /** | ||||
|      * Atomically increments the current usage count for the given connection. | ||||
|      * | ||||
|      * @param connection | ||||
|      *     The connection which is being used. | ||||
|      * All active connections to a connection group having a given identifier. | ||||
|      */ | ||||
|     private void addActiveConnection(Connection connection, ConnectionRecord record) { | ||||
|         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. | ||||
|      * If a combination of incrementUsage() and decrementUsage() calls result | ||||
|      * in the usage counter being reduced to zero, it is guaranteed that one | ||||
|      * 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); | ||||
|  | ||||
|         } | ||||
|     } | ||||
|     private final ActiveConnectionMultimap activeConnectionGroups = new ActiveConnectionMultimap(); | ||||
|  | ||||
|     /** | ||||
|      * Acquires possibly-exclusive access to any one of the given connections | ||||
| @@ -224,6 +172,10 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | ||||
|         // Create record for active connection | ||||
|         final ActiveConnectionRecord activeConnection = new ActiveConnectionRecord(user); | ||||
|  | ||||
|         // Get relevant identifiers | ||||
|         final String identifier = connection.getIdentifier(); | ||||
|         final String parentIdentifier = connection.getParentIdentifier(); | ||||
|          | ||||
|         // Generate configuration from available data | ||||
|         GuacamoleConfiguration config = new GuacamoleConfiguration(); | ||||
|  | ||||
| @@ -232,7 +184,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | ||||
|         config.setProtocol(model.getProtocol()); | ||||
|  | ||||
|         // Set parameters from associated data | ||||
|         Collection<ParameterModel> parameters = parameterMapper.select(connection.getIdentifier()); | ||||
|         Collection<ParameterModel> parameters = parameterMapper.select(identifier); | ||||
|         for (ParameterModel parameter : parameters) | ||||
|             config.setParameter(parameter.getName(), parameter.getValue()); | ||||
|  | ||||
| @@ -247,7 +199,8 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | ||||
|         try { | ||||
|  | ||||
|             // Record new active connection | ||||
|             addActiveConnection(connection, activeConnection); | ||||
|             activeConnections.put(identifier, activeConnection); | ||||
|             activeConnectionGroups.put(parentIdentifier, activeConnection); | ||||
|  | ||||
|             // Return newly-reserved connection | ||||
|             return new ConfiguredGuacamoleSocket( | ||||
| @@ -265,7 +218,8 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | ||||
|                     super.close(); | ||||
|                      | ||||
|                     // Release connection upon close | ||||
|                     removeActiveConnection(connection, activeConnection); | ||||
|                     activeConnections.remove(identifier, activeConnection); | ||||
|                     activeConnectionGroups.remove(parentIdentifier, activeConnection); | ||||
|                     release(user, connection); | ||||
|  | ||||
|                     UserModel userModel = user.getUser().getModel(); | ||||
| @@ -274,7 +228,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | ||||
|                     // Copy user information and timestamps into new record | ||||
|                     recordModel.setUserID(userModel.getObjectID()); | ||||
|                     recordModel.setUsername(userModel.getIdentifier()); | ||||
|                     recordModel.setConnectionIdentifier(connection.getIdentifier()); | ||||
|                     recordModel.setConnectionIdentifier(identifier); | ||||
|                     recordModel.setStartDate(activeConnection.getStartDate()); | ||||
|                     recordModel.setEndDate(new Date()); | ||||
|  | ||||
| @@ -291,7 +245,8 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | ||||
|         catch (GuacamoleException e) { | ||||
|  | ||||
|             // Atomically release access to connection | ||||
|             removeActiveConnection(connection, activeConnection); | ||||
|             activeConnections.remove(identifier, activeConnection); | ||||
|             activeConnectionGroups.remove(parentIdentifier, activeConnection); | ||||
|             release(user, connection); | ||||
|  | ||||
|             throw e; | ||||
| @@ -314,18 +269,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | ||||
|  | ||||
|     @Override | ||||
|     public List<ConnectionRecord> getActiveConnections(Connection connection) { | ||||
|         synchronized (activeConnections) { | ||||
|  | ||||
|             String identifier = connection.getIdentifier(); | ||||
|  | ||||
|             // Get set of active connection records | ||||
|             LinkedList<ConnectionRecord> connections = activeConnections.get(identifier); | ||||
|             if (connections != null) | ||||
|                 return Collections.unmodifiableList(connections); | ||||
|  | ||||
|             return Collections.EMPTY_LIST; | ||||
|  | ||||
|         } | ||||
|         return activeConnections.get(connection.getIdentifier()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -362,8 +306,13 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | ||||
|  | ||||
|     @Override | ||||
|     public List<ConnectionRecord> getActiveConnections(ConnectionGroup connectionGroup) { | ||||
|         // STUB | ||||
|  | ||||
|         // 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,128 @@ | ||||
| /* | ||||
|  * 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.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| 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, LinkedList<ConnectionRecord>> records = | ||||
|             new HashMap<String, LinkedList<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 | ||||
|             LinkedList<ConnectionRecord> connections = records.get(identifier); | ||||
|             if (connections == null) { | ||||
|                 connections = new LinkedList<ConnectionRecord>(); | ||||
|                 records.put(identifier, connections); | ||||
|             } | ||||
|  | ||||
|             // Add active connection | ||||
|             connections.addFirst(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 | ||||
|             LinkedList<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 the current list of active connection records associated with | ||||
|      * the object having the given identifier. The list will be sorted in | ||||
|      * ascending order of connection age. If there are no such connections, an | ||||
|      * empty list is returned. | ||||
|      * | ||||
|      * @param identifier | ||||
|      *     The identifier of the object to check. | ||||
|      * | ||||
|      * @return | ||||
|      *     An immutable list of records associated with the object having the | ||||
|      *     given identifier, or an empty list if there are no such records. | ||||
|      */ | ||||
|     public List<ConnectionRecord> get(String identifier) { | ||||
|         synchronized (records) { | ||||
|  | ||||
|             // Get set of active connection records | ||||
|             LinkedList<ConnectionRecord> connections = records.get(identifier); | ||||
|             if (connections != null) | ||||
|                 return Collections.unmodifiableList(connections); | ||||
|  | ||||
|             return Collections.EMPTY_LIST; | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user