From e54d36cae56c22f1c23e6afe1e1aedb6aa0a1d4e Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 24 Jul 2016 16:02:12 -0700 Subject: [PATCH] GUACAMOLE-5: Implement thread-safe automatic cleanup of a group of shared objects. --- .../jdbc/sharing/SharedObjectManager.java | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedObjectManager.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedObjectManager.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedObjectManager.java new file mode 100644 index 000000000..c04148510 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedObjectManager.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.sharing; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Provides thread-safe registration and cleanup of a growing set of objects. + * Each SharedObjectManager can track arbitrarily-many objects, each registered + * with the register() function. A SharedObjectManager tracks objects until it + * is invalidated, after which all registered objects are cleaned up. Attempts + * to register new objects after the SharedObjectManager has been invalidated + * will cause the provided object to be immediately cleaned up. + * + * @author Michael Jumper + * @param + * The type of object managed by this SharedObjectManager. + */ +public abstract class SharedObjectManager { + + /** + * Whether this SharedObjectManager has been invalidated. + */ + private final AtomicBoolean invalidated = new AtomicBoolean(false); + + /** + * The collection of all objects being tracked by this SharedObjectManager. + */ + private final Queue objects = new ConcurrentLinkedQueue(); + + /** + * Cleans up the given object. This function is invoked exactly once on all + * tracked objects after invalidate() is called, and exactly once for any + * call to register() which occurs after invalidate() was called. + * + * @param object + * The object to cleanup. + */ + protected abstract void cleanup(T object); + + /** + * Invokes the cleanup() function on all tracked objects, removing each + * object from the underlying collection. It is guaranteed that cleanup() + * will be invoked only once for each object, even if multiple calls to + * cleanupAll() are running concurrently, and that the underlying collection + * will be empty after all calls to cleanupAll() complete. + */ + private void cleanupAll() { + + T current; + + // Remove all objects from underlying collection, cleaning up each + // object individually + while ((current = objects.poll()) != null) + cleanup(current); + + } + + /** + * Registers the given object with this SharedObjectManager such that it is + * cleaned up once the SharedObjectManager is invalidated. If the + * SharedObjectManager has already been invalidated, the object will be + * cleaned up immediately. + * + * @param object + * The object to register with this SharedObjectManager. + */ + public void register(T object) { + + // If already invalidated (or invalidation is in progress), avoid adding + // the object unnecessarily - just cleanup now + if (invalidated.get()) { + cleanup(object); + return; + } + + // Store provided object + objects.add(object); + + // If collection was invalidated while object was being added, recheck + // the underlying collection and cleanup + if (invalidated.get()) + cleanupAll(); + + } + + /** + * Invalidates this SharedObjectManager, cleaning up any registered objects + * and preventing future registration of objects. If attempts to register + * objects are made after this function is invoked, those objects will be + * immediately cleaned up. + */ + public void invalidate() { + + // Mark collection as invalidated, but do not bother cleaning up if + // already invalidated + if (!invalidated.compareAndSet(false, true)) + return; + + // Clean up all stored objects + cleanupAll(); + + } + +}