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.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; | ||||||
| @@ -98,63 +95,14 @@ 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. |  | ||||||
|      * 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); |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Acquires possibly-exclusive access to any one of the given connections |      * 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 |         // 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(); | ||||||
|  |  | ||||||
| @@ -232,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()); | ||||||
|  |  | ||||||
| @@ -247,7 +199,8 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | |||||||
|         try { |         try { | ||||||
|  |  | ||||||
|             // Record new active connection |             // Record new active connection | ||||||
|             addActiveConnection(connection, activeConnection); |             activeConnections.put(identifier, activeConnection); | ||||||
|  |             activeConnectionGroups.put(parentIdentifier, activeConnection); | ||||||
|  |  | ||||||
|             // Return newly-reserved connection |             // Return newly-reserved connection | ||||||
|             return new ConfiguredGuacamoleSocket( |             return new ConfiguredGuacamoleSocket( | ||||||
| @@ -265,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(); | ||||||
| @@ -274,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()); | ||||||
|  |  | ||||||
| @@ -291,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; | ||||||
| @@ -314,18 +269,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<ConnectionRecord> getActiveConnections(Connection connection) { |     public List<ConnectionRecord> getActiveConnections(Connection connection) { | ||||||
|         synchronized (activeConnections) { |         return activeConnections.get(connection.getIdentifier()); | ||||||
|  |  | ||||||
|             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; |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @@ -362,8 +306,13 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<ConnectionRecord> getActiveConnections(ConnectionGroup connectionGroup) { |     public List<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,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