/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.util;
import com.liferay.portal.kernel.concurrent.ConcurrentReferenceKeyHashMap;
import com.liferay.portal.kernel.concurrent.ConcurrentReferenceValueHashMap;
import com.liferay.portal.kernel.memory.FinalizeManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.concurrent.ConcurrentMap;
/**
* @author Shuyang Zhou
*/
public class ProxyUtil {
public static InvocationHandler getInvocationHandler(Object proxy) {
if (!isProxyClass(proxy.getClass())) {
throw new IllegalArgumentException("Not a proxy instance");
}
try {
return (InvocationHandler)_invocationHandlerField.get(proxy);
}
catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
public static Class<?> getProxyClass(
ClassLoader classLoader, Class<?>... interfaceClasses) {
ConcurrentMap<LookupKey, Class<?>> classReferences =
_classReferences.get(classLoader);
if (classReferences == null) {
classReferences = new ConcurrentReferenceValueHashMap<>(
FinalizeManager.WEAK_REFERENCE_FACTORY);
ConcurrentMap<LookupKey, Class<?>> oldClassReferences =
_classReferences.putIfAbsent(classLoader, classReferences);
if (oldClassReferences != null) {
classReferences = oldClassReferences;
}
}
LookupKey lookupKey = new LookupKey(interfaceClasses);
Class<?> clazz = classReferences.get(lookupKey);
if (clazz == null) {
synchronized (classReferences) {
clazz = classReferences.get(lookupKey);
if (clazz == null) {
clazz = Proxy.getProxyClass(classLoader, interfaceClasses);
classReferences.put(lookupKey, clazz);
}
}
}
if (!_constructors.containsKey(clazz)) {
Constructor<?> constructor = null;
try {
constructor = clazz.getConstructor(_argumentsClazz);
constructor.setAccessible(true);
}
catch (Exception e) {
throw new InternalError(e.toString());
}
_constructors.putIfAbsent(clazz, constructor);
}
return clazz;
}
public static boolean isProxyClass(Class<?> clazz) {
if (clazz == null) {
throw new NullPointerException();
}
return _constructors.containsKey(clazz);
}
public static Object newProxyInstance(
ClassLoader classLoader, Class<?>[] interfaces,
InvocationHandler invocationHandler) {
Constructor<?> constructor = _constructors.get(
getProxyClass(classLoader, interfaces));
try {
return constructor.newInstance(new Object[] {invocationHandler});
}
catch (Exception e) {
throw new InternalError(e.toString());
}
}
private static final Class<?>[] _argumentsClazz = {InvocationHandler.class};
private static final ConcurrentMap
<ClassLoader, ConcurrentMap<LookupKey, Class<?>>> _classReferences =
new ConcurrentReferenceKeyHashMap<>(
FinalizeManager.WEAK_REFERENCE_FACTORY);
private static final ConcurrentMap<Class<?>, Constructor<?>> _constructors =
new ConcurrentReferenceKeyHashMap<>(
new ConcurrentReferenceValueHashMap<Class<?>, Constructor<?>>(
FinalizeManager.WEAK_REFERENCE_FACTORY),
FinalizeManager.WEAK_REFERENCE_FACTORY);
private static final Field _invocationHandlerField;
static {
try {
_invocationHandlerField = ReflectionUtil.getDeclaredField(
Proxy.class, "h");
}
catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
private static class LookupKey {
@Override
public boolean equals(Object obj) {
LookupKey lookupKey = (LookupKey)obj;
if (_interfaces.length != lookupKey._interfaces.length) {
return false;
}
for (int i = 0; i < _interfaces.length; i++) {
if (_interfaces[i] != lookupKey._interfaces[i]) {
return false;
}
}
return true;
}
@Override
public int hashCode() {
return _hashCode;
}
private LookupKey(Class<?>[] interfaces) {
_interfaces = interfaces;
int hashCode = 0;
for (Class<?> clazz : interfaces) {
hashCode = HashUtil.hash(hashCode, clazz.getName());
}
_hashCode = hashCode;
}
private final int _hashCode;
private final Class<?>[] _interfaces;
}
}