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