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.lar.backgroundtask;
016    
017    import com.liferay.portal.NoSuchLayoutException;
018    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskResult;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.exception.SystemException;
021    import com.liferay.portal.kernel.lar.ExportImportDateUtil;
022    import com.liferay.portal.kernel.lar.ExportImportHelperUtil;
023    import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
024    import com.liferay.portal.kernel.lar.MissingReferences;
025    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
026    import com.liferay.portal.kernel.lar.lifecycle.ExportImportLifecycleConstants;
027    import com.liferay.portal.kernel.lar.lifecycle.ExportImportLifecycleManager;
028    import com.liferay.portal.kernel.log.Log;
029    import com.liferay.portal.kernel.log.LogFactoryUtil;
030    import com.liferay.portal.kernel.util.DateRange;
031    import com.liferay.portal.kernel.util.FileUtil;
032    import com.liferay.portal.kernel.util.GetterUtil;
033    import com.liferay.portal.kernel.util.MapUtil;
034    import com.liferay.portal.kernel.util.StreamUtil;
035    import com.liferay.portal.model.BackgroundTask;
036    import com.liferay.portal.model.ExportImportConfiguration;
037    import com.liferay.portal.model.Layout;
038    import com.liferay.portal.security.auth.HttpPrincipal;
039    import com.liferay.portal.service.ExportImportConfigurationLocalServiceUtil;
040    import com.liferay.portal.service.LayoutLocalServiceUtil;
041    import com.liferay.portal.service.http.LayoutServiceHttp;
042    import com.liferay.portal.service.http.StagingServiceHttp;
043    import com.liferay.portal.util.PropsValues;
044    
045    import java.io.File;
046    import java.io.FileInputStream;
047    import java.io.Serializable;
048    
049    import java.util.ArrayList;
050    import java.util.Date;
051    import java.util.List;
052    import java.util.Map;
053    
054    /**
055     * @author Mate Thurzo
056     */
057    public class LayoutRemoteStagingBackgroundTaskExecutor
058            extends BaseStagingBackgroundTaskExecutor {
059    
060            public LayoutRemoteStagingBackgroundTaskExecutor() {
061                    setBackgroundTaskStatusMessageTranslator(
062                            new LayoutStagingBackgroundTaskStatusMessageTranslator());
063            }
064    
065            @Override
066            public BackgroundTaskResult execute(BackgroundTask backgroundTask)
067                    throws PortalException {
068    
069                    Map<String, Serializable> taskContextMap =
070                            backgroundTask.getTaskContextMap();
071    
072                    long exportImportConfigurationId = MapUtil.getLong(
073                            taskContextMap, "exportImportConfigurationId");
074    
075                    ExportImportConfiguration exportImportConfiguration =
076                            ExportImportConfigurationLocalServiceUtil.
077                                    getExportImportConfiguration(exportImportConfigurationId);
078    
079                    Map<String, Serializable> settingsMap =
080                            exportImportConfiguration.getSettingsMap();
081    
082                    long sourceGroupId = MapUtil.getLong(settingsMap, "sourceGroupId");
083                    boolean privateLayout = MapUtil.getBoolean(
084                            settingsMap, "privateLayout");
085    
086                    initThreadLocals(sourceGroupId, privateLayout);
087    
088                    Map<Long, Boolean> layoutIdMap = (Map<Long, Boolean>)settingsMap.get(
089                            "layoutIdMap");
090                    Map<String, String[]> parameterMap =
091                            (Map<String, String[]>)settingsMap.get("parameterMap");
092                    long remoteGroupId = MapUtil.getLong(settingsMap, "remoteGroupId");
093                    DateRange dateRange = ExportImportDateUtil.getDateRange(
094                            exportImportConfiguration,
095                            ExportImportDateUtil.RANGE_FROM_LAST_PUBLISH_DATE);
096                    HttpPrincipal httpPrincipal = (HttpPrincipal)taskContextMap.get(
097                            "httpPrincipal");
098    
099                    clearBackgroundTaskStatus(backgroundTask);
100    
101                    long stagingRequestId = 0;
102    
103                    File file = null;
104                    FileInputStream fileInputStream = null;
105                    MissingReferences missingReferences = null;
106    
107                    try {
108                            ExportImportThreadLocal.setLayoutStagingInProcess(true);
109    
110                            ExportImportLifecycleManager.fireExportImportLifecycleEvent(
111                                    ExportImportLifecycleConstants.
112                                            EVENT_PUBLICATION_LAYOUT_REMOTE_STARTED,
113                                    exportImportConfiguration);
114    
115                            file = exportLayoutsAsFile(
116                                    sourceGroupId, privateLayout, layoutIdMap, parameterMap,
117                                    remoteGroupId, dateRange.getStartDate(), dateRange.getEndDate(),
118                                    httpPrincipal);
119    
120                            String checksum = FileUtil.getMD5Checksum(file);
121    
122                            fileInputStream = new FileInputStream(file);
123    
124                            stagingRequestId = StagingServiceHttp.createStagingRequest(
125                                    httpPrincipal, remoteGroupId, checksum);
126    
127                            byte[] bytes =
128                                    new byte[PropsValues.STAGING_REMOTE_TRANSFER_BUFFER_SIZE];
129    
130                            int i = 0;
131                            int j = 0;
132    
133                            String numberFormat = String.format(
134                                    "%%0%dd",
135                                    String.valueOf(
136                                            (int)(file.length() / bytes.length)).length() + 1);
137    
138                            while ((i = fileInputStream.read(bytes)) >= 0) {
139                                    String fileName =
140                                            file.getName() + String.format(numberFormat, j++);
141    
142                                    if (i < PropsValues.STAGING_REMOTE_TRANSFER_BUFFER_SIZE) {
143                                            byte[] tempBytes = new byte[i];
144    
145                                            System.arraycopy(bytes, 0, tempBytes, 0, i);
146    
147                                            StagingServiceHttp.updateStagingRequest(
148                                                    httpPrincipal, stagingRequestId, fileName, tempBytes);
149                                    }
150                                    else {
151                                            StagingServiceHttp.updateStagingRequest(
152                                                    httpPrincipal, stagingRequestId, fileName, bytes);
153                                    }
154    
155                                    bytes =
156                                            new byte[PropsValues.STAGING_REMOTE_TRANSFER_BUFFER_SIZE];
157                            }
158    
159                            markBackgroundTask(
160                                    backgroundTask.getBackgroundTaskId(), "exported");
161    
162                            missingReferences = StagingServiceHttp.validateStagingRequest(
163                                    httpPrincipal, stagingRequestId, privateLayout, parameterMap);
164    
165                            markBackgroundTask(
166                                    backgroundTask.getBackgroundTaskId(), "validated");
167    
168                            StagingServiceHttp.publishStagingRequest(
169                                    httpPrincipal, stagingRequestId, privateLayout, parameterMap);
170    
171                            boolean updateLastPublishDate = MapUtil.getBoolean(
172                                    parameterMap, PortletDataHandlerKeys.UPDATE_LAST_PUBLISH_DATE);
173    
174                            if (updateLastPublishDate) {
175                                    ExportImportDateUtil.updateLastPublishDate(
176                                            sourceGroupId, privateLayout, dateRange,
177                                            dateRange.getEndDate());
178                            }
179    
180                            ExportImportLifecycleManager.fireExportImportLifecycleEvent(
181                                    ExportImportLifecycleConstants.
182                                            EVENT_PUBLICATION_LAYOUT_REMOTE_SUCCEEDED,
183                                    exportImportConfiguration);
184                    }
185                    catch (Throwable t) {
186                            ExportImportLifecycleManager.fireExportImportLifecycleEvent(
187                                    ExportImportLifecycleConstants.
188                                            EVENT_PUBLICATION_LAYOUT_REMOTE_FAILED,
189                                    exportImportConfiguration);
190    
191                            if (_log.isDebugEnabled()) {
192                                    _log.debug(t, t);
193                            }
194                            else if (_log.isWarnEnabled()) {
195                                    _log.warn("Unable to publish layout: " + t.getMessage());
196                            }
197    
198                            throw new SystemException(t);
199                    }
200                    finally {
201                            ExportImportThreadLocal.setLayoutStagingInProcess(false);
202    
203                            StreamUtil.cleanUp(fileInputStream);
204    
205                            FileUtil.delete(file);
206    
207                            if (stagingRequestId > 0) {
208                                    StagingServiceHttp.cleanUpStagingRequest(
209                                            httpPrincipal, stagingRequestId);
210                            }
211                    }
212    
213                    return processMissingReferences(
214                            backgroundTask.getBackgroundTaskId(), missingReferences);
215            }
216    
217            protected File exportLayoutsAsFile(
218                            long sourceGroupId, boolean privateLayout,
219                            Map<Long, Boolean> layoutIdMap, Map<String, String[]> parameterMap,
220                            long remoteGroupId, Date startDate, Date endDate,
221                            HttpPrincipal httpPrincipal)
222                    throws PortalException {
223    
224                    List<Layout> layouts = new ArrayList<Layout>();
225    
226                    if (layoutIdMap != null) {
227                            for (Map.Entry<Long, Boolean> entry : layoutIdMap.entrySet()) {
228                                    long plid = GetterUtil.getLong(String.valueOf(entry.getKey()));
229                                    boolean includeChildren = entry.getValue();
230    
231                                    Layout layout = LayoutLocalServiceUtil.getLayout(plid);
232    
233                                    if (!layouts.contains(layout)) {
234                                            layouts.add(layout);
235                                    }
236    
237                                    List<Layout> parentLayouts = getMissingRemoteParentLayouts(
238                                            httpPrincipal, layout, remoteGroupId);
239    
240                                    for (Layout parentLayout : parentLayouts) {
241                                            if (!layouts.contains(parentLayout)) {
242                                                    layouts.add(parentLayout);
243                                            }
244                                    }
245    
246                                    if (includeChildren) {
247                                            for (Layout childLayout : layout.getAllChildren()) {
248                                                    if (!layouts.contains(childLayout)) {
249                                                            layouts.add(childLayout);
250                                                    }
251                                            }
252                                    }
253                            }
254                    }
255    
256                    long[] layoutIds = ExportImportHelperUtil.getLayoutIds(layouts);
257    
258                    return LayoutLocalServiceUtil.exportLayoutsAsFile(
259                            sourceGroupId, privateLayout, layoutIds, parameterMap, startDate,
260                            endDate);
261            }
262    
263            /**
264             * @see com.liferay.portal.lar.ExportImportHelperImpl#getMissingParentLayouts(
265             *      Layout, long)
266             */
267            protected List<Layout> getMissingRemoteParentLayouts(
268                            HttpPrincipal httpPrincipal, Layout layout, long remoteGroupId)
269                    throws PortalException {
270    
271                    List<Layout> missingRemoteParentLayouts = new ArrayList<Layout>();
272    
273                    long parentLayoutId = layout.getParentLayoutId();
274    
275                    while (parentLayoutId > 0) {
276                            Layout parentLayout = LayoutLocalServiceUtil.getLayout(
277                                    layout.getGroupId(), layout.isPrivateLayout(), parentLayoutId);
278    
279                            try {
280                                    LayoutServiceHttp.getLayoutByUuidAndGroupId(
281                                            httpPrincipal, parentLayout.getUuid(), remoteGroupId,
282                                            parentLayout.getPrivateLayout());
283    
284                                    // If one parent is found, all others are assumed to exist
285    
286                                    break;
287                            }
288                            catch (NoSuchLayoutException nsle) {
289                                    missingRemoteParentLayouts.add(parentLayout);
290    
291                                    parentLayoutId = parentLayout.getParentLayoutId();
292                            }
293                    }
294    
295                    return missingRemoteParentLayouts;
296            }
297    
298            private static Log _log = LogFactoryUtil.getLog(
299                    LayoutRemoteStagingBackgroundTaskExecutor.class);
300    
301    }