001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.util;
016    
017    import com.liferay.portal.kernel.concurrent.ConcurrentReferenceKeyHashMap;
018    import com.liferay.portal.kernel.concurrent.ConcurrentReferenceValueHashMap;
019    import com.liferay.portal.kernel.memory.FinalizeManager;
020    
021    import java.lang.reflect.Constructor;
022    import java.lang.reflect.Field;
023    import java.lang.reflect.InvocationHandler;
024    import java.lang.reflect.Proxy;
025    
026    import java.util.concurrent.ConcurrentMap;
027    
028    /**
029     * @author Shuyang Zhou
030     */
031    public class ProxyUtil {
032    
033            public static InvocationHandler getInvocationHandler(Object proxy) {
034                    if (!isProxyClass(proxy.getClass())) {
035                            throw new IllegalArgumentException("Not a proxy instance");
036                    }
037    
038                    try {
039                            return (InvocationHandler)_invocationHandlerField.get(proxy);
040                    }
041                    catch (Exception e) {
042                            throw new IllegalArgumentException(e);
043                    }
044            }
045    
046            public static Class<?> getProxyClass(
047                    ClassLoader classLoader, Class<?>... interfaceClasses) {
048    
049                    ConcurrentMap<LookupKey, Class<?>> classReferences =
050                            _classReferences.get(classLoader);
051    
052                    if (classReferences == null) {
053                            classReferences =
054                                    new ConcurrentReferenceValueHashMap<LookupKey, Class<?>>(
055                                            FinalizeManager.WEAK_REFERENCE_FACTORY);
056    
057                            ConcurrentMap<LookupKey, Class<?>> oldClassReferences =
058                                    _classReferences.putIfAbsent(classLoader, classReferences);
059    
060                            if (oldClassReferences != null) {
061                                    classReferences = oldClassReferences;
062                            }
063                    }
064    
065                    LookupKey lookupKey = new LookupKey(interfaceClasses);
066    
067                    Class<?> clazz = classReferences.get(lookupKey);
068    
069                    if (clazz == null) {
070                            synchronized(classReferences) {
071                                    clazz = classReferences.get(lookupKey);
072    
073                                    if (clazz == null) {
074                                            clazz = Proxy.getProxyClass(classLoader, interfaceClasses);
075    
076                                            classReferences.put(lookupKey, clazz);
077                                    }
078                            }
079                    }
080    
081                    Constructor<?> constructor = null;
082    
083                    try {
084                            constructor = clazz.getConstructor(_argumentsClazz);
085    
086                            constructor.setAccessible(true);
087                    }
088                    catch (Exception e) {
089                            throw new InternalError(e.toString());
090                    }
091    
092                    _constructors.putIfAbsent(clazz, constructor);
093    
094                    return clazz;
095            }
096    
097            public static boolean isProxyClass(Class<?> clazz) {
098                    if (clazz == null) {
099                            throw new NullPointerException();
100                    }
101    
102                    return _constructors.containsKey(clazz);
103            }
104    
105            public static Object newProxyInstance(
106                    ClassLoader classLoader, Class<?>[] interfaces,
107                    InvocationHandler invocationHandler) {
108    
109                    Constructor<?> constructor = _constructors.get(
110                            getProxyClass(classLoader, interfaces));
111    
112                    try {
113                            return constructor.newInstance(new Object[] {invocationHandler});
114                    }
115                    catch (Exception e) {
116                            throw new InternalError(e.toString());
117                    }
118            }
119    
120            private static Class<?>[] _argumentsClazz = {InvocationHandler.class};
121            private static ConcurrentMap
122                    <ClassLoader, ConcurrentMap<LookupKey, Class<?>>> _classReferences =
123                            new ConcurrentReferenceKeyHashMap
124                                    <ClassLoader, ConcurrentMap<LookupKey, Class<?>>>(
125                                            FinalizeManager.WEAK_REFERENCE_FACTORY);
126            private static ConcurrentMap<Class<?>, Constructor<?>> _constructors =
127                    new ConcurrentReferenceKeyHashMap<Class<?>, Constructor<?>>(
128                            FinalizeManager.WEAK_REFERENCE_FACTORY);
129            private static Field _invocationHandlerField;
130    
131            static {
132                    try {
133                            _invocationHandlerField = ReflectionUtil.getDeclaredField(
134                                    Proxy.class, "h");
135                    }
136                    catch (Exception e) {
137                            throw new ExceptionInInitializerError(e);
138                    }
139            }
140    
141            private static class LookupKey {
142    
143                    public LookupKey(Class<?>[] interfaces) {
144                            _interfaces = interfaces;
145    
146                            _hashCode = 1;
147    
148                            for (Class<?> clazz : interfaces) {
149                                    String name = clazz.getName();
150    
151                                    _hashCode = HashUtil.hash(_hashCode, name.hashCode());
152                            }
153                    }
154    
155                    @Override
156                    public boolean equals(Object obj) {
157                            LookupKey lookupKey = (LookupKey)obj;
158    
159                            if (_interfaces.length != lookupKey._interfaces.length) {
160                                    return false;
161                            }
162    
163                            for (int i = 0; i < _interfaces.length; i++) {
164                                    if (_interfaces[i] != lookupKey._interfaces[i]) {
165                                            return false;
166                                    }
167                            }
168    
169                            return true;
170                    }
171    
172                    @Override
173                    public int hashCode() {
174                            return _hashCode;
175                    }
176    
177                    private int _hashCode;
178                    private final Class<?>[] _interfaces;
179    
180            }
181    
182    }