/* * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; /** * This abstract ReentrantContextProvider helper class manages the creation, * storage, and retrieval of concrete ReentrantContext instances which can be * subclassed to hold cached contextual data. * * It supports reentrancy as every call to acquire() provides a new unique context * instance that must later be returned for reuse by a call to release(ctx) * (typically in a try/finally block). * * It has a couple of abstract implementations which store references in a queue * and/or thread-local storage. * The Providers can be configured to hold ReentrantContext instances in memory * using hard, soft or weak references. * * The acquire() and release() methods are used to retrieve and return the contexts. * * The {@code newContext()} method remains abstract in all implementations and * must be provided by the module to create a new subclass of ReentrantContext * with the appropriate contextual data in it. * * Sample Usage: * - create a subclass ReentrantContextImpl to hold the thread state: * * static final class ReentrantContextImpl extends ReentrantContext { * // specific cached data * } * * - create the appropriate ReentrantContextProvider: * * private static final ReentrantContextProvider contextProvider = * new ReentrantContextProviderTL(ReentrantContextProvider.REF_WEAK) * { * @Override * protected ReentrantContextImpl newContext() { * return new ReentrantContextImpl(); * } * }; * ... * void someMethod() { * ReentrantContextImpl ctx = contextProvider.acquire(); * try { * // use the context * } finally { * contextProvider.release(ctx); * } * } * * @param ReentrantContext subclass * * @see ReentrantContext */ public abstract class ReentrantContextProvider { // thread-local storage: inactive static final byte USAGE_TL_INACTIVE = 0; // thread-local storage: in use static final byte USAGE_TL_IN_USE = 1; // CLQ storage static final byte USAGE_CLQ = 2; // hard reference public static final int REF_HARD = 0; // soft reference public static final int REF_SOFT = 1; // weak reference public static final int REF_WEAK = 2; /* members */ // internal reference type private final int refType; /** * Create a new ReentrantContext provider using the given reference type * among hard, soft or weak * * @param refType reference type */ protected ReentrantContextProvider(final int refType) { this.refType = refType; } /** * Create a new ReentrantContext instance * * @return new ReentrantContext instance */ protected abstract K newContext(); /** * Give a ReentrantContext instance for the current thread * * @return ReentrantContext instance */ public abstract K acquire(); /** * Restore the given ReentrantContext instance for reuse * * @param ctx ReentrantContext instance */ public abstract void release(K ctx); @SuppressWarnings("unchecked") protected final Reference getOrCreateReference(final K ctx) { if (ctx.reference == null) { // Create the reference: switch (refType) { case REF_HARD: ctx.reference = new HardReference(ctx); break; case REF_SOFT: ctx.reference = new SoftReference(ctx); break; default: case REF_WEAK: ctx.reference = new WeakReference(ctx); break; } } return (Reference) ctx.reference; } /* Missing HardReference implementation */ static final class HardReference extends WeakReference { // kept strong reference: private final V strongRef; HardReference(final V referent) { // no referent needed for the parent WeakReference: super(null); this.strongRef = referent; } @Override public V get() { return strongRef; } } }