001    /**
002     * Copyright (c) 2000-2012 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.io.Deserializer;
018    import com.liferay.portal.kernel.io.Serializer;
019    
020    import java.io.Externalizable;
021    import java.io.IOException;
022    import java.io.ObjectInput;
023    import java.io.ObjectOutput;
024    
025    import java.lang.reflect.Method;
026    
027    import java.nio.ByteBuffer;
028    
029    import java.util.Arrays;
030    
031    /**
032     * @author Brian Wing Shun Chan
033     * @author Shuyang Zhou
034     */
035    public class MethodKey implements Externalizable {
036    
037            /**
038             * The empty constructor is required by {@link java.io.Externalizable}. Do
039             * not use this for any other purpose.
040             */
041            public MethodKey() {
042            }
043    
044            public MethodKey(
045                    Class<?> declaringClass, String methodName,
046                    Class<?>... parameterTypes) {
047    
048                    _declaringClass = declaringClass;
049                    _methodName = methodName;
050                    _parameterTypes = parameterTypes;
051            }
052    
053            public MethodKey(Method method) {
054                    this(
055                            method.getDeclaringClass(), method.getName(),
056                            method.getParameterTypes());
057            }
058    
059            @Override
060            public boolean equals(Object obj) {
061                    if (this == obj) {
062                            return true;
063                    }
064    
065                    if (!(obj instanceof MethodKey)) {
066                            return false;
067                    }
068    
069                    MethodKey methodKey = (MethodKey)obj;
070    
071                    if ((_declaringClass == methodKey._declaringClass) &&
072                            Validator.equals(_methodName, methodKey._methodName) &&
073                            Arrays.equals(_parameterTypes, methodKey._parameterTypes)) {
074    
075                            return true;
076                    }
077    
078                    return false;
079            }
080    
081            public Class<?> getDeclaringClass() {
082                    return _declaringClass;
083            }
084    
085            public Method getMethod() throws NoSuchMethodException {
086                    return MethodCache.get(this);
087            }
088    
089            public String getMethodName() {
090                    return _methodName;
091            }
092    
093            public Class<?>[] getParameterTypes() {
094                    return _parameterTypes;
095            }
096    
097            @Override
098            public int hashCode() {
099    
100                    // Using the same hash algorithm as java.lang.reflect.Method
101    
102                    return _declaringClass.getName().hashCode() ^ _methodName.hashCode();
103            }
104    
105            public void readExternal(ObjectInput objectInput)
106                    throws ClassNotFoundException, IOException {
107    
108                    int size = objectInput.readInt();
109    
110                    byte[] data = new byte[size];
111    
112                    objectInput.readFully(data);
113    
114                    Deserializer deserializer = new Deserializer(ByteBuffer.wrap(data));
115    
116                    _declaringClass = deserializer.readObject();
117                    _methodName = deserializer.readString();
118    
119                    int parameterTypesLength = deserializer.readInt();
120    
121                    _parameterTypes = new Class<?>[parameterTypesLength];
122    
123                    for (int i = 0; i < parameterTypesLength; i++) {
124                            _parameterTypes[i] = deserializer.readObject();
125                    }
126            }
127    
128            @Override
129            public String toString() {
130                    if (_toString != null) {
131                            return _toString;
132                    }
133    
134                    StringBundler sb = new StringBundler(4 + _parameterTypes.length * 2);
135    
136                    sb.append(_declaringClass.getName());
137                    sb.append(StringPool.PERIOD);
138                    sb.append(_methodName);
139                    sb.append(StringPool.OPEN_PARENTHESIS);
140    
141                    for (Class<?> parameterType : _parameterTypes) {
142                            sb.append(parameterType.getName());
143                            sb.append(StringPool.COMMA);
144                    }
145    
146                    sb.setIndex(sb.index() - 1);
147    
148                    sb.append(StringPool.CLOSE_PARENTHESIS);
149    
150                    _toString = sb.toString();
151    
152                    return _toString;
153            }
154    
155            public MethodKey transform(ClassLoader classLoader)
156                    throws ClassNotFoundException {
157    
158                    Class<?> declaringClass = classLoader.loadClass(
159                            _declaringClass.getName());
160    
161                    Class<?>[] parameterTypes = new Class<?>[_parameterTypes.length];
162    
163                    for (int i = 0; i < _parameterTypes.length; i++) {
164                            parameterTypes[i] = classLoader.loadClass(
165                                    _parameterTypes[i].getName());
166                    }
167    
168                    return new MethodKey(declaringClass, _methodName, parameterTypes);
169            }
170    
171            public void writeExternal(ObjectOutput objectOutput) throws IOException {
172                    Serializer serializer = new Serializer();
173    
174                    serializer.writeObject(_declaringClass);
175                    serializer.writeString(_methodName);
176                    serializer.writeInt(_parameterTypes.length);
177    
178                    for (Class<?> parameterType : _parameterTypes) {
179                            serializer.writeObject(parameterType);
180                    }
181    
182                    ByteBuffer byteBuffer = serializer.toByteBuffer();
183    
184                    objectOutput.writeInt(byteBuffer.remaining());
185                    objectOutput.write(
186                            byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining());
187            }
188    
189            private Class<?> _declaringClass;
190    
191            private String _methodName;
192            private Class<?>[] _parameterTypes;
193    
194            // Transient cache
195    
196            private String _toString;
197    
198    }