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.backgroundtask.messaging;
016    
017    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskConstants;
018    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskExecutor;
019    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskResult;
020    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskStatusMessageTranslator;
021    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskStatusRegistryUtil;
022    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskThreadLocal;
023    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskThreadLocalManager;
024    import com.liferay.portal.kernel.backgroundtask.ClassLoaderAwareBackgroundTaskExecutor;
025    import com.liferay.portal.kernel.backgroundtask.SerialBackgroundTaskExecutor;
026    import com.liferay.portal.kernel.backgroundtask.ThreadLocalAwareBackgroundTaskExecutor;
027    import com.liferay.portal.kernel.lock.DuplicateLockException;
028    import com.liferay.portal.kernel.log.Log;
029    import com.liferay.portal.kernel.log.LogFactoryUtil;
030    import com.liferay.portal.kernel.messaging.BaseMessageListener;
031    import com.liferay.portal.kernel.messaging.DestinationNames;
032    import com.liferay.portal.kernel.messaging.Message;
033    import com.liferay.portal.kernel.messaging.MessageBusUtil;
034    import com.liferay.portal.kernel.util.ClassLoaderUtil;
035    import com.liferay.portal.kernel.util.InstanceFactory;
036    import com.liferay.portal.kernel.util.StackTraceUtil;
037    import com.liferay.portal.kernel.util.StringUtil;
038    import com.liferay.portal.kernel.util.Validator;
039    import com.liferay.portal.model.BackgroundTask;
040    import com.liferay.portal.service.BackgroundTaskLocalServiceUtil;
041    import com.liferay.portal.service.ServiceContext;
042    
043    /**
044     * @author Michael C. Han
045     */
046    public class BackgroundTaskMessageListener extends BaseMessageListener {
047    
048            public void setBackgroundTaskThreadLocalManager(
049                    BackgroundTaskThreadLocalManager backgroundTaskThreadLocalManager) {
050    
051                    _backgroundTaskThreadLocalManager = backgroundTaskThreadLocalManager;
052            }
053    
054            @Override
055            protected void doReceive(Message message) throws Exception {
056                    long backgroundTaskId = (Long)message.get("backgroundTaskId");
057    
058                    BackgroundTaskThreadLocal.setBackgroundTaskId(backgroundTaskId);
059    
060                    ServiceContext serviceContext = new ServiceContext();
061    
062                    BackgroundTask backgroundTask =
063                            BackgroundTaskLocalServiceUtil.amendBackgroundTask(
064                                    backgroundTaskId, null,
065                                    BackgroundTaskConstants.STATUS_IN_PROGRESS, serviceContext);
066    
067                    if (backgroundTask == null) {
068                            return;
069                    }
070    
071                    BackgroundTaskExecutor backgroundTaskExecutor = null;
072                    BackgroundTaskStatusMessageListener
073                            backgroundTaskStatusMessageListener = null;
074    
075                    int status = backgroundTask.getStatus();
076                    String statusMessage = null;
077    
078                    try {
079                            ClassLoader classLoader = ClassLoaderUtil.getPortalClassLoader();
080    
081                            String servletContextNames =
082                                    backgroundTask.getServletContextNames();
083    
084                            if (Validator.isNotNull(servletContextNames)) {
085                                    classLoader = ClassLoaderUtil.getAggregatePluginsClassLoader(
086                                            StringUtil.split(servletContextNames), false);
087                            }
088    
089                            backgroundTaskExecutor =
090                                    (BackgroundTaskExecutor)InstanceFactory.newInstance(
091                                            classLoader, backgroundTask.getTaskExecutorClassName());
092    
093                            backgroundTaskExecutor = wrapBackgroundTaskExecutor(
094                                    backgroundTaskExecutor, classLoader);
095    
096                            BackgroundTaskStatusRegistryUtil.registerBackgroundTaskStatus(
097                                    backgroundTaskId);
098    
099                            BackgroundTaskStatusMessageTranslator
100                                    backgroundTaskStatusMessageTranslator =
101                                            backgroundTaskExecutor.
102                                                    getBackgroundTaskStatusMessageTranslator();
103    
104                            if (backgroundTaskStatusMessageTranslator != null) {
105                                    backgroundTaskStatusMessageListener =
106                                            new BackgroundTaskStatusMessageListener(
107                                                    backgroundTaskId,
108                                                    backgroundTaskStatusMessageTranslator);
109    
110                                    MessageBusUtil.registerMessageListener(
111                                            DestinationNames.BACKGROUND_TASK_STATUS,
112                                            backgroundTaskStatusMessageListener);
113                            }
114    
115                            backgroundTask = BackgroundTaskLocalServiceUtil.fetchBackgroundTask(
116                                    backgroundTask.getBackgroundTaskId());
117    
118                            BackgroundTaskResult backgroundTaskResult =
119                                    backgroundTaskExecutor.execute(backgroundTask);
120    
121                            status = backgroundTaskResult.getStatus();
122                            statusMessage = backgroundTaskResult.getStatusMessage();
123                    }
124                    catch (DuplicateLockException e) {
125                            status = BackgroundTaskConstants.STATUS_QUEUED;
126                    }
127                    catch (Exception e) {
128                            status = BackgroundTaskConstants.STATUS_FAILED;
129    
130                            if (backgroundTaskExecutor != null) {
131                                    statusMessage = backgroundTaskExecutor.handleException(
132                                            backgroundTask, e);
133                            }
134    
135                            if (_log.isInfoEnabled()) {
136                                    if (statusMessage != null) {
137                                            statusMessage = statusMessage.concat(
138                                                    StackTraceUtil.getStackTrace(e));
139                                    }
140                                    else {
141                                            statusMessage = StackTraceUtil.getStackTrace(e);
142                                    }
143                            }
144    
145                            _log.error("Unable to execute background task", e);
146                    }
147                    finally {
148                            BackgroundTaskLocalServiceUtil.amendBackgroundTask(
149                                    backgroundTaskId, null, status, statusMessage, serviceContext);
150    
151                            BackgroundTaskStatusRegistryUtil.unregisterBackgroundTaskStatus(
152                                    backgroundTaskId);
153    
154                            if (backgroundTaskStatusMessageListener != null) {
155                                    MessageBusUtil.unregisterMessageListener(
156                                            DestinationNames.BACKGROUND_TASK_STATUS,
157                                            backgroundTaskStatusMessageListener);
158                            }
159    
160                            Message responseMessage = new Message();
161    
162                            responseMessage.put(
163                                    "backgroundTaskId", backgroundTask.getBackgroundTaskId());
164                            responseMessage.put("name", backgroundTask.getName());
165                            responseMessage.put("status", status);
166                            responseMessage.put(
167                                    "taskExecutorClassName",
168                                    backgroundTask.getTaskExecutorClassName());
169    
170                            MessageBusUtil.sendMessage(
171                                    DestinationNames.BACKGROUND_TASK_STATUS, responseMessage);
172                    }
173            }
174    
175            protected BackgroundTaskExecutor wrapBackgroundTaskExecutor(
176                    BackgroundTaskExecutor backgroundTaskExecutor,
177                    ClassLoader classLoader) {
178    
179                    if (classLoader != ClassLoaderUtil.getPortalClassLoader()) {
180                            backgroundTaskExecutor = new ClassLoaderAwareBackgroundTaskExecutor(
181                                    backgroundTaskExecutor, classLoader);
182                    }
183    
184                    if (backgroundTaskExecutor.isSerial()) {
185                            backgroundTaskExecutor = new SerialBackgroundTaskExecutor(
186                                    backgroundTaskExecutor);
187                    }
188    
189                    backgroundTaskExecutor = new ThreadLocalAwareBackgroundTaskExecutor(
190                            backgroundTaskExecutor, _backgroundTaskThreadLocalManager);
191    
192                    return backgroundTaskExecutor;
193            }
194    
195            private static final Log _log = LogFactoryUtil.getLog(
196                    BackgroundTaskMessageListener.class);
197    
198            private BackgroundTaskThreadLocalManager _backgroundTaskThreadLocalManager;
199    
200    }