Java tutorial
/* * 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 com.sworddance.util; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.Callable; import static org.apache.commons.lang.StringUtils.*; import static com.sworddance.util.CUtilities.*; /** * Weakly held object. Allows surrounding code to be unaware of WeakReference usage. * @author patmoore * */ public class WeakProxy { /** * Create a WeakReference that is wrapped in a Proxy implementing the interfaces. * @param <T> * @param referent * @param interfaces optional - uses referent.getClass().getInterfaces() if not supplied. * @return null if referent == null otherwise returns a proxy implementing the interfaces */ public static <T> T newProxyInstance(final Object referent, Class<?>... interfaces) { return (T) newProxyInstance(referent, null, interfaces); } public static <T> T newProxyInstance(Callable<T> restoreCallable, Class<?>... interfaces) { return newProxyInstance(null, restoreCallable, interfaces); } @SuppressWarnings("unchecked") public static <T> T newProxyInstance(final Object referent, Callable<T> restoreCallable, Class<?>... interfaces) { if (referent == null && restoreCallable == null) { return null; } else { Class<?> clazz = getFirst(interfaces); T actualReferent = (T) getActual(referent); if (clazz == null) { if (actualReferent == null) { actualReferent = invokeCallable(restoreCallable); } ApplicationIllegalArgumentException.notNull(actualReferent, "referent must be not null if there are no listed classes"); clazz = actualReferent.getClass(); interfaces = clazz.getInterfaces(); } Reference<T> objectRef = newWeakReference(actualReferent); ProxyInvocationHandler<T> invocationHandler = new ProxyInvocationHandler<T>(objectRef, restoreCallable, interfaces); T t = invocationHandler.newProxyInstance(clazz.getClassLoader()); return t; } } /** * * @param proxy a {@link Reference} or proxy created by {@link #newProxyInstance(Object, Class...)} * @return true if there is an actual object to access. */ public static boolean isWired(Object proxy) { return getActual(proxy) != null; } /** * * @param <T> * @param proxy * @return the actual object that is wrapped by {@link Reference} and {@link #newProxyInstance(Object, Class...)} created * objects. */ @SuppressWarnings("unchecked") public static <T> T getActual(Object proxy) { Object actual = proxy; while (actual != null) { if (Proxy.isProxyClass(actual.getClass())) { InvocationHandler invocationHandler = Proxy.getInvocationHandler(actual); if (invocationHandler instanceof ProxyInvocationHandler<?>) { actual = ((ProxyInvocationHandler<?>) invocationHandler).getActual(); } else { break; } } else if (actual instanceof Reference<?>) { actual = getActual(getReferent((Reference<T>) actual)); } else { break; } } return (T) actual; } /** * @param actual * @return */ private static <T> T invokeCallable(Callable<T> restoreCallable) { if (restoreCallable == null) { return null; } try { return restoreCallable.call(); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new ApplicationGeneralException(e); } } public static <T> WeakReference<T> newWeakReference(T referent) { if (referent == null) { return null; } else { return new WeakReference<T>(referent); } } public static <T> T getReferent(Reference<T> reference) { if (reference == null) { return null; } else { return reference.get(); } } protected static class ProxyInvocationHandler<T> implements InvocationHandler { private final Callable<T> restoreCallable; private Reference<T> objectRef; private final String stringDescription; private final Class<?>[] interfaces; protected ProxyInvocationHandler(Reference<T> objectRef, Callable<T> restoreCallable, Class<?>[] interfaces) { this.restoreCallable = restoreCallable; this.objectRef = objectRef; this.stringDescription = "implements = {" + join(interfaces, ", ") + "}"; this.interfaces = interfaces; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (isWired()) { T actual = getActual(); return method.invoke(actual, args); } else { throw new ApplicationNullPointerException("weakreference was dropped"); } } /** * @param objectRef the objectRef to set * @return this */ @SuppressWarnings("hiding") public ProxyInvocationHandler<T> initObjectRef(Reference<T> objectRef) { this.setObjectRef(objectRef); return this; } /** * @param objectRef the objectRef to set */ public void setObjectRef(Reference<T> objectRef) { this.objectRef = objectRef; } /** * @return the objectRef */ public Reference<T> getObjectRef() { return objectRef; } /** * @return the objectRef */ public T getActual() { T actual = getReferent(getObjectRef()); if (actual == null) { actual = invokeCallable(restoreCallable); setActual(actual); } return actual; } public void setActual(T actual) { setObjectRef(newWeakReference(actual)); } /** * @return the interfaces */ public Class<?>[] getInterfaces() { return interfaces; } public boolean isWired() { return getActual() != null; } @Override public String toString() { return this.stringDescription + " object=" + this.getActual(); } @SuppressWarnings("unchecked") public T newProxyInstance(ClassLoader classLoader) { return (T) Proxy.newProxyInstance(classLoader, interfaces, this); } } }