From: Robert Varga Date: Mon, 6 Sep 2021 22:14:59 +0000 (+0200) Subject: Remove RecursiveObjectLeaker X-Git-Tag: v8.0.0~251 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=8bacd7a91200c37acc34e756ea9099a0d4e406ef;p=yangtools.git Remove RecursiveObjectLeaker This is a remnant of infrastructure needed to make circular object graphs work. It has been deprecated for removal in version 7.0.0, now remove it. JIRA: YANGTOOLS-1318 Change-Id: I8f6590b5398317a6c24d4b06956161b747795de6 Signed-off-by: Robert Varga --- diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/RecursiveObjectLeaker.java b/common/util/src/main/java/org/opendaylight/yangtools/util/RecursiveObjectLeaker.java deleted file mode 100644 index 14ede64cd5..0000000000 --- a/common/util/src/main/java/org/opendaylight/yangtools/util/RecursiveObjectLeaker.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.yangtools.util; - -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.annotations.Beta; -import java.util.AbstractMap.SimpleEntry; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.Map.Entry; -import org.eclipse.jdt.annotation.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Thread-local hack to make recursive extensions work without too much hassle. The idea is that prior to instantiating - * an extension, the definition object checks whether it is already present on the stack, recorded object is returned. - * - *

- * If it is not, it will push itself to the stack as unresolved and invoke the constructor. The constructor's lowermost - * class calls to this class and if the topmost entry is not resolved, it will leak itself. - * - *

- * Upon return from the constructor, the topmost entry is removed and if the queue is empty, the thread-local variable - * will be cleaned up. - * - *

- * WARNING: BE CAREFUL WHEN USING THIS CLASS. IT LEAKS OBJECTS WHICH ARE NOT COMPLETELY INITIALIZED. - * - *

- * WARNING: THIS CLASS LEAVES THREAD-LOCAL RESIDUE. MAKE SURE IT IS OKAY OR CALL {@link #cleanup()} IN APPROPRIATE - * PLACES. - * - *

- * THIS CLASS IS EXTREMELY DANGEROUS (okay, not as much as sun.misc.unsafe). YOU HAVE BEEN WARNED. IF SOMETHING BREAKS - * IT IS PROBABLY YOUR FAULT AND YOU ARE ON YOUR OWN. - * - * @author Robert Varga - * @deprecated This class is not used anywhere anymore and is scheduled for removal in the next major release. - */ -@Beta -@Deprecated(forRemoval = true) -// FIXME: 8.0.0: remove this class -public final class RecursiveObjectLeaker { - // Logging note. Only keys passed can be logged, as objects beng resolved may not be properly constructed. - private static final Logger LOG = LoggerFactory.getLogger(RecursiveObjectLeaker.class); - - // Initial value is set to null on purpose, so we do not allocate anything (aside the map) - private static final ThreadLocal>> STACK = new ThreadLocal<>(); - - private RecursiveObjectLeaker() { - // Hidden on purpose - } - - // Key is checked for identity - public static void beforeConstructor(final Object key) { - Deque> stack = STACK.get(); - if (stack == null) { - // Biased: this class is expected to be rarely and shallowly used - stack = new ArrayDeque<>(1); - STACK.set(stack); - } - - LOG.debug("Resolving key {}", key); - stack.push(new SimpleEntry<>(key, null)); - } - - // Can potentially store a 'null' mapping. Make sure cleanup() is called - public static void inConstructor(final Object obj) { - final Deque> stack = STACK.get(); - if (stack != null) { - final Entry top = stack.peek(); - if (top != null) { - if (top.getValue() == null) { - LOG.debug("Resolved key {}", top.getKey()); - top.setValue(obj); - } - } else { - LOG.info("Cleaned stale empty stack", new Exception()); - STACK.set(null); - } - } else { - LOG.trace("No thread stack"); - } - } - - // Make sure to call this from a finally block - public static void afterConstructor(final Object key) { - final Deque> stack = STACK.get(); - checkState(stack != null, "No stack allocated when completing %s", key); - - final Entry top = stack.pop(); - if (stack.isEmpty()) { - LOG.trace("Removed empty thread stack"); - STACK.set(null); - } - - checkState(key == top.getKey(), "Expected key %s, have %s", top.getKey(), key); - checkState(top.getValue() != null, ""); - } - - // BEWARE: this method returns incpmpletely-initialized objects (that is the purpose of this class). - // - // BE VERY CAREFUL WHAT OBJECT STATE YOU TOUCH - public static @Nullable T lookup(final Object key, final Class requiredClass) { - final Deque> stack = STACK.get(); - if (stack != null) { - for (Entry e : stack) { - // Keys are treated as identities - if (key == e.getKey()) { - checkState(e.getValue() != null, "Object for %s is not resolved", key); - LOG.debug("Looked up key {}", e.getKey()); - return requiredClass.cast(e.getValue()); - } - } - } - - return null; - } - - // Be sure to call this in from a finally block when bulk processing is done, so that this class can be unloaded - public static void cleanup() { - STACK.remove(); - LOG.debug("Removed thread state"); - } -}