/* * JBoss, Home of Professional Open Source. * Copyright 2014 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * Licensed 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.jboss.modules.ref; import java.lang.ref.ReferenceQueue; /** * A set of utility methods for reference types. */ public final class References { @SuppressWarnings({ "RawUseOfParameterizedType" }) private static final Reference NULL = new Reference() { public Object get() { return null; } public Object getAttachment() { return null; } public void clear() { } public Type getType() { return Type.NULL; } public String toString() { return "NULL reference"; } }; private References() { } static final class ReaperThread extends Thread { static final ReferenceQueue<Object> REAPER_QUEUE = new ReferenceQueue<Object>(); static { final ReaperThread thr = new ReaperThread(); thr.setName("Reference Reaper"); thr.setDaemon(true); thr.start(); } public void run() { for (;;) try { final java.lang.ref.Reference<? extends Object> ref = REAPER_QUEUE.remove(); if (ref instanceof Reapable) { reap((Reapable<?, ?>) ref); } } catch (InterruptedException ignored) { } catch (Throwable ignored) { } } @SuppressWarnings({ "unchecked" }) private static <T, A> void reap(final Reapable<T, A> reapable) { reapable.getReaper().reap((Reference<T, A>) reapable); } } /** * Create a reference of a given type with the provided value and attachment. If the reference type is * {@link Reference.Type#STRONG} or {@link Reference.Type#NULL} then the reaper argument is ignored. If * the reference type is {@link Reference.Type#NULL} then the value and attachment arguments are ignored. * * @param type the reference type * @param value the reference value * @param attachment the attachment value * @param reaper the reaper to use, if any * @param <T> the reference value type * @param <A> the reference attachment type * @return the reference */ public static <T, A> Reference<T, A> create(Reference.Type type, T value, A attachment, Reaper<T, A> reaper) { switch (type) { case STRONG: return new StrongReference<T, A>(value, attachment); case WEAK: return new WeakReference<T, A>(value, attachment, reaper); case PHANTOM: return new PhantomReference<T, A>(value, attachment, reaper); case SOFT: return new SoftReference<T, A>(value, attachment, reaper); case NULL: return getNullReference(); default: throw new IllegalStateException(); } } /** * Create a reference of a given type with the provided value and attachment. If the reference type is * {@link Reference.Type#STRONG} or {@link Reference.Type#NULL} then the reference queue argument is ignored. If * the reference type is {@link Reference.Type#NULL} then the value and attachment arguments are ignored. * * @param type the reference type * @param value the reference value * @param attachment the attachment value * @param referenceQueue the reference queue to use, if any * @param <T> the reference value type * @param <A> the reference attachment type * @return the reference */ public static <T, A> Reference<T, A> create(Reference.Type type, T value, A attachment, ReferenceQueue<? super T> referenceQueue) { switch (type) { case STRONG: return new StrongReference<T, A>(value, attachment); case WEAK: return new WeakReference<T, A>(value, attachment, referenceQueue); case PHANTOM: return new PhantomReference<T, A>(value, attachment, referenceQueue); case SOFT: return new SoftReference<T, A>(value, attachment, referenceQueue); case NULL: return getNullReference(); default: throw new IllegalStateException(); } } /** * Create a reference of a given type with the provided value and attachment. If the reference type is * {@link Reference.Type#PHANTOM} then this method will throw an {@code IllegalArgumentException} because * such references are not constructable without a queue or reaper. If the reference type is * {@link Reference.Type#NULL} then the value and attachment arguments are ignored. * * @param type the reference type * @param value the reference value * @param attachment the attachment value * @param <T> the reference value type * @param <A> the reference attachment type * @return the reference * @throws IllegalArgumentException if the reference type is {@link Reference.Type#PHANTOM} */ public static <T, A> Reference<T, A> create(Reference.Type type, T value, A attachment) throws IllegalArgumentException { switch (type) { case STRONG: return new StrongReference<T, A>(value, attachment); case WEAK: return new WeakReference<T, A>(value, attachment); case PHANTOM: throw new IllegalArgumentException("Phantom reference may not be created without a queue or reaper"); case SOFT: return new SoftReference<T, A>(value, attachment); case NULL: return getNullReference(); default: throw new IllegalStateException(); } } /** * Get a null reference. This reference type is always cleared and does not retain an attachment; as such * there is only one single instance of it. * * @param <T> the reference value type * @param <A> the attachment value type * @return the null reference */ @SuppressWarnings({ "unchecked" }) public static <T, A> Reference<T, A> getNullReference() { return (Reference<T, A>) NULL; } }