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