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.messaging.proxy;
016    
017    import com.liferay.portal.kernel.annotation.AnnotationLocator;
018    import com.liferay.portal.kernel.util.MethodKey;
019    import com.liferay.portal.kernel.util.StringBundler;
020    
021    import java.io.Externalizable;
022    import java.io.IOException;
023    import java.io.ObjectInput;
024    import java.io.ObjectOutput;
025    
026    import java.lang.reflect.InvocationTargetException;
027    import java.lang.reflect.Method;
028    
029    import java.util.Arrays;
030    import java.util.Map;
031    import java.util.concurrent.ConcurrentHashMap;
032    
033    /**
034     * @author Micha Kiener
035     * @author Michael C. Han
036     * @author Brian Wing Shun Chan
037     * @author Shuyang Zhou
038     */
039    public class ProxyRequest implements Externalizable {
040    
041            /**
042             * The empty constructor is required by {@link Externalizable}. Do not use
043             * this for any other purpose.
044             */
045            public ProxyRequest() {
046                    _local = false;
047            }
048    
049            public ProxyRequest(Method method, Object[] arguments) throws Exception {
050                    _method = method;
051                    _arguments = arguments;
052    
053                    if (method.getReturnType() != Void.TYPE) {
054                            _hasReturnValue = true;
055                    }
056    
057                    boolean[] localAndSynchronous = _localAndSynchronousMap.get(method);
058    
059                    if (localAndSynchronous == null) {
060                            localAndSynchronous = new boolean[2];
061    
062                            MessagingProxy messagingProxy = AnnotationLocator.locate(
063                                    method, method.getDeclaringClass(), MessagingProxy.class);
064    
065                            if (messagingProxy != null) {
066                                    if (messagingProxy.local()) {
067                                            localAndSynchronous[0] = true;
068                                    }
069    
070                                    ProxyMode proxyMode = messagingProxy.mode();
071    
072                                    if (proxyMode.equals(ProxyMode.SYNC)) {
073                                            localAndSynchronous[1] = true;
074                                    }
075                            }
076    
077                            _localAndSynchronousMap.put(method, localAndSynchronous);
078                    }
079    
080                    _local = localAndSynchronous[0];
081                    _synchronous = localAndSynchronous[1];
082            }
083    
084            public Object execute(Object object) throws Exception {
085                    try {
086                            return _method.invoke(object, _arguments);
087                    }
088                    catch (InvocationTargetException ite) {
089                            Throwable t = ite.getCause();
090    
091                            if (t instanceof Exception) {
092                                    throw (Exception)t;
093                            }
094                            else {
095                                    throw new Exception(t);
096                            }
097                    }
098            }
099    
100            public Object[] getArguments() {
101                    return _arguments;
102            }
103    
104            public boolean hasReturnValue() {
105                    return _hasReturnValue;
106            }
107    
108            public boolean isLocal() {
109                    return _local;
110            }
111    
112            public boolean isSynchronous() {
113                    return _synchronous;
114            }
115    
116            @Override
117            public void readExternal(ObjectInput objectInput)
118                    throws ClassNotFoundException, IOException {
119    
120                    _arguments = (Object[])objectInput.readObject();
121                    _hasReturnValue = objectInput.readBoolean();
122    
123                    MethodKey methodKey = (MethodKey)objectInput.readObject();
124    
125                    try {
126                            _method = methodKey.getMethod();
127                    }
128                    catch (NoSuchMethodException nsme) {
129                            throw new IOException(nsme);
130                    }
131    
132                    _synchronous = objectInput.readBoolean();
133            }
134    
135            @Override
136            public String toString() {
137                    StringBundler sb = new StringBundler(9);
138    
139                    sb.append("{arguments=");
140                    sb.append(Arrays.toString(_arguments));
141                    sb.append(", hasReturnValue=");
142                    sb.append(_hasReturnValue);
143                    sb.append(", method=");
144                    sb.append(_method);
145                    sb.append(", synchronous");
146                    sb.append(_synchronous);
147                    sb.append("}");
148    
149                    return sb.toString();
150            }
151    
152            @Override
153            public void writeExternal(ObjectOutput objectOutput) throws IOException {
154                    objectOutput.writeObject(_arguments);
155                    objectOutput.writeBoolean(_hasReturnValue);
156                    objectOutput.writeObject(new MethodKey(_method));
157                    objectOutput.writeBoolean(_synchronous);
158            }
159    
160            private static final Map<Method, boolean[]> _localAndSynchronousMap =
161                    new ConcurrentHashMap<>();
162    
163            private Object[] _arguments;
164            private boolean _hasReturnValue;
165            private final boolean _local;
166            private Method _method;
167            private boolean _synchronous;
168    
169    }