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