001    /**
002     * Copyright (c) 2000-2013 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.messaging.async;
016    
017    import com.liferay.portal.kernel.bean.IdentifiableBean;
018    import com.liferay.portal.kernel.bean.PortalBeanLocatorUtil;
019    import com.liferay.portal.kernel.bean.PortletBeanLocatorUtil;
020    import com.liferay.portal.kernel.util.ClassLoaderPool;
021    import com.liferay.portal.kernel.util.MethodHandler;
022    import com.liferay.portal.kernel.util.MethodKey;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.util.ClassLoaderUtil;
025    import com.liferay.portal.util.PortalUtil;
026    
027    import java.io.Externalizable;
028    import java.io.IOException;
029    import java.io.ObjectInput;
030    import java.io.ObjectOutput;
031    
032    import org.aopalliance.intercept.MethodInvocation;
033    
034    /**
035     * @author Shuyang Zhou
036     */
037    public class AsyncRunnable implements Externalizable, Runnable {
038    
039            public AsyncRunnable() {
040            }
041    
042            public AsyncRunnable(MethodInvocation methodInvocation) {
043                    _methodInvocation = methodInvocation;
044            }
045    
046            @Override
047            public void readExternal(ObjectInput objectInput)
048                    throws ClassNotFoundException, IOException {
049    
050                    _methodHandler = (MethodHandler)objectInput.readObject();
051            }
052    
053            @Override
054            public void run() {
055                    try {
056                            if (_methodInvocation != null) {
057                                    _methodInvocation.proceed();
058                            }
059                            else {
060                                    AsyncInvokeThreadLocal.setEnabled(true);
061    
062                                    try {
063                                            _methodHandler.invoke(null);
064                                    }
065                                    finally {
066                                            AsyncInvokeThreadLocal.setEnabled(false);
067                                    }
068                            }
069                    }
070                    catch (Throwable t) {
071                            throw new RuntimeException(t);
072                    }
073            }
074    
075            @Override
076            public void writeExternal(ObjectOutput objectOutput) throws IOException {
077                    MethodHandler methodHandler = _methodHandler;
078    
079                    if (methodHandler == null) {
080                            Thread currentThread = Thread.currentThread();
081    
082                            ClassLoader contextClassLoader =
083                                    currentThread.getContextClassLoader();
084    
085                            String servletContextName = ClassLoaderPool.getContextName(
086                                    contextClassLoader);
087    
088                            methodHandler = new MethodHandler(
089                                    _methodInvocation.getMethod(),
090                                    _methodInvocation.getArguments());
091    
092                            Object thisObject = _methodInvocation.getThis();
093    
094                            IdentifiableBean identifiableBean = (IdentifiableBean)thisObject;
095    
096                            Class<?> identifiableBeanClass = identifiableBean.getClass();
097    
098                            ClassLoader identifiableBeanClassLoader =
099                                    identifiableBeanClass.getClassLoader();
100    
101                            String identifiableBeanServletContextName =
102                                    ClassLoaderPool.getContextName(identifiableBeanClassLoader);
103    
104                            String beanIdentifier = identifiableBean.getBeanIdentifier();
105    
106                            methodHandler = new MethodHandler(
107                                    _invokeMethodKey, methodHandler, servletContextName,
108                                    identifiableBeanServletContextName, beanIdentifier);
109                    }
110    
111                    objectOutput.writeObject(methodHandler);
112            }
113    
114            @SuppressWarnings("unused")
115            private static Object _invoke(
116                            MethodHandler methodHandler, String servletContextName,
117                            String identifiableBeanServletContextName, String beanIdentifier)
118                    throws Exception {
119    
120                    if (Validator.isNull(servletContextName)) {
121                            if (Validator.isNull(beanIdentifier)) {
122                                    return methodHandler.invoke(true);
123                            }
124    
125                            Object bean = PortalBeanLocatorUtil.locate(beanIdentifier);
126    
127                            return methodHandler.invoke(bean);
128                    }
129    
130                    ClassLoader contextClassLoader =
131                            ClassLoaderUtil.getContextClassLoader();
132    
133                    try {
134                            ClassLoader classLoader = ClassLoaderPool.getClassLoader(
135                                    servletContextName);
136    
137                            ClassLoaderUtil.setContextClassLoader(classLoader);
138    
139                            if (Validator.isNull(beanIdentifier)) {
140                                    return methodHandler.invoke(true);
141                            }
142    
143                            Object bean = null;
144    
145                            if (identifiableBeanServletContextName.equals(
146                                            PortalUtil.getServletContextName())) {
147    
148                                    bean = PortalBeanLocatorUtil.locate(beanIdentifier);
149                            }
150                            else {
151                                    bean = PortletBeanLocatorUtil.locate(
152                                            servletContextName, beanIdentifier);
153                            }
154    
155                            return methodHandler.invoke(bean);
156                    }
157                    finally {
158                            ClassLoaderUtil.setContextClassLoader(contextClassLoader);
159                    }
160            }
161    
162            private static MethodKey _invokeMethodKey = new MethodKey(
163                    AsyncRunnable.class, "_invoke", MethodHandler.class, String.class,
164                    String.class, String.class);
165    
166            private MethodHandler _methodHandler;
167            private MethodInvocation _methodInvocation;
168    
169    }