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